如何在HSSF(Apache POI)的现有Excel中的两行之间插入一行
不知何故,我设法在现有的Excel文件中的两行之间创build新的行。 问题是,一些格式不包括在行的移动。
其中一个,就是在转移过程中隐藏的行并不是相对的。 我的意思是(例如),从20到30的行是隐藏的,但是当创build新行时仍然在那里形成。 在插入/创build新行时,隐藏行也必须移动,它应该是21到31。
另一件事是,工作表中另一个不在单元格中的对象。 像文本框不会在创build新行之后移动。 它像这些对象的位置是固定的。 但是我希望它移动,就像我在Excel中插入新行或粘贴行一样。 如果有插入新行的function,请告诉我。
这是我现在所拥有的,只是我的代码片段。
HSSFWorkbook wb = new HSSFWorkbook(template); //template is the source of file HSSFSheet sheet = wb.getSheet("SAMPLE"); HSSFRow newRow; HSSFCell cellData; int createNewRowAt = 9; //Add the new row between row 9 and 10 sheet.shiftRows(createNewRowAt, sheet.getLastRowNum(), 1, true, false); newRow = sheet.createRow(createNewRowAt); newRow = sheet.getRow(createNewRowAt);
如果复制和粘贴行是可能的,这将是很大的帮助。 但是我已经在这里问了,找不到解决办法。 所以我决定创build一个临时解决scheme。 我完成了,但有这样的问题。
任何帮助都感激不尽。 谢谢!
助手function,从这里无耻地复制行
import org.apache.poi.hssf.usermodel.*; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.util.CellRangeAddress; import java.io.FileInputStream; import java.io.FileOutputStream; public class RowCopy { public static void main(String[] args) throws Exception{ HSSFWorkbook workbook = new HSSFWorkbook(new FileInputStream("c:/input.xls")); HSSFSheet sheet = workbook.getSheet("Sheet1"); copyRow(workbook, sheet, 0, 1); FileOutputStream out = new FileOutputStream("c:/output.xls"); workbook.write(out); out.close(); } private static void copyRow(HSSFWorkbook workbook, HSSFSheet worksheet, int sourceRowNum, int destinationRowNum) { // Get the source / new row HSSFRow newRow = worksheet.getRow(destinationRowNum); HSSFRow sourceRow = worksheet.getRow(sourceRowNum); // If the row exist in destination, push down all rows by 1 else create a new row if (newRow != null) { worksheet.shiftRows(destinationRowNum, worksheet.getLastRowNum(), 1); } else { newRow = worksheet.createRow(destinationRowNum); } // Loop through source columns to add to new row for (int i = 0; i < sourceRow.getLastCellNum(); i++) { // Grab a copy of the old/new cell HSSFCell oldCell = sourceRow.getCell(i); HSSFCell newCell = newRow.createCell(i); // If the old cell is null jump to next cell if (oldCell == null) { newCell = null; continue; } // Copy style from old cell and apply to new cell HSSFCellStyle newCellStyle = workbook.createCellStyle(); newCellStyle.cloneStyleFrom(oldCell.getCellStyle()); ; newCell.setCellStyle(newCellStyle); // If there is a cell comment, copy if (oldCell.getCellComment() != null) { newCell.setCellComment(oldCell.getCellComment()); } // If there is a cell hyperlink, copy if (oldCell.getHyperlink() != null) { newCell.setHyperlink(oldCell.getHyperlink()); } // Set the cell data type newCell.setCellType(oldCell.getCellType()); // Set the cell data value switch (oldCell.getCellType()) { case Cell.CELL_TYPE_BLANK: newCell.setCellValue(oldCell.getStringCellValue()); break; case Cell.CELL_TYPE_BOOLEAN: newCell.setCellValue(oldCell.getBooleanCellValue()); break; case Cell.CELL_TYPE_ERROR: newCell.setCellErrorValue(oldCell.getErrorCellValue()); break; case Cell.CELL_TYPE_FORMULA: newCell.setCellFormula(oldCell.getCellFormula()); break; case Cell.CELL_TYPE_NUMERIC: newCell.setCellValue(oldCell.getNumericCellValue()); break; case Cell.CELL_TYPE_STRING: newCell.setCellValue(oldCell.getRichStringCellValue()); break; } } // If there are are any merged regions in the source row, copy to new row for (int i = 0; i < worksheet.getNumMergedRegions(); i++) { CellRangeAddress cellRangeAddress = worksheet.getMergedRegion(i); if (cellRangeAddress.getFirstRow() == sourceRow.getRowNum()) { CellRangeAddress newCellRangeAddress = new CellRangeAddress(newRow.getRowNum(), (newRow.getRowNum() + (cellRangeAddress.getLastRow() - cellRangeAddress.getFirstRow() )), cellRangeAddress.getFirstColumn(), cellRangeAddress.getLastColumn()); worksheet.addMergedRegion(newCellRangeAddress); } } } }
参照Qwerty的答案 ,你可以通过重新使用cellStyle
来避免膨胀XL的大小。 而当types是CELL_TYPE_BLANK
, getStringCellValue
返回""
而不是null
。
private static void copyRow(Sheet worksheet, int sourceRowNum, int destinationRowNum) { // Get the source / new row Row newRow = worksheet.getRow(destinationRowNum); Row sourceRow = worksheet.getRow(sourceRowNum); // If the row exist in destination, push down all rows by 1 else create a new row if (newRow != null) { worksheet.shiftRows(destinationRowNum, worksheet.getLastRowNum(), 1); } else { newRow = worksheet.createRow(destinationRowNum); } // Loop through source columns to add to new row for (int i = 0; i < sourceRow.getLastCellNum(); i++) { // Grab a copy of the old/new cell Cell oldCell = sourceRow.getCell(i); Cell newCell = newRow.createCell(i); // If the old cell is null jump to next cell if (oldCell == null) { newCell = null; continue; } // Use old cell style newCell.setCellStyle(oldCell.getCellStyle()); // If there is a cell comment, copy if (newCell.getCellComment() != null) { newCell.setCellComment(oldCell.getCellComment()); } // If there is a cell hyperlink, copy if (oldCell.getHyperlink() != null) { newCell.setHyperlink(oldCell.getHyperlink()); } // Set the cell data type newCell.setCellType(oldCell.getCellType()); // Set the cell data value switch (oldCell.getCellType()) { case Cell.CELL_TYPE_BLANK: break; case Cell.CELL_TYPE_BOOLEAN: newCell.setCellValue(oldCell.getBooleanCellValue()); break; case Cell.CELL_TYPE_ERROR: newCell.setCellErrorValue(oldCell.getErrorCellValue()); break; case Cell.CELL_TYPE_FORMULA: newCell.setCellFormula(oldCell.getCellFormula()); break; case Cell.CELL_TYPE_NUMERIC: newCell.setCellValue(oldCell.getNumericCellValue()); break; case Cell.CELL_TYPE_STRING: newCell.setCellValue(oldCell.getRichStringCellValue()); break; } } }
对于新行中“更新”的公式,由于所有的复制都是在移位之后进行的,因此旧行(现在是从新行开始的一个索引)已经将其公式移位,所以将其复制到新行将使新行引用旧行单元格。 解决方法是在转换之前parsing公式,然后应用这些(一个简单的String数组就可以完成这项工作,我相信你可以用几行代码)。
function开始时:
ArrayList<String> fArray = new ArrayList<String>(); Row origRow = sheet.getRow(sourceRow); for (int i = 0; i < origRow.getLastCellNum(); i++) { if (origRow.getCell(i) != null && origRow.getCell(i).getCellType() == Cell.CELL_TYPE_FORMULA) fArray.add(origRow.getCell(i).getCellFormula()); else fArray.add(null); }
然后,在将公式应用于单元格时:
newCell.setCellFormula(fArray.get(i));
我在下面的实现中合并了一些其他答案和评论,并使用Apache POI v3.9进行了testing。
我只有一个rownum
参数,因为我向下移动目标行并将其复制到新的空行中。 公式按预期方式处理,不会逐字复制,但有一个例外:对复制行上方单元格的引用不会更新; 解决方法是用本文build议的使用INDIRECT()
计算的引用replace这些显式引用(如果有的话)。
protected void copyRow(Sheet worksheet, int rowNum) { Row sourceRow = worksheet.getRow(rowNum); //Save the text of any formula before they are altered by row shifting String[] formulasArray = new String[sourceRow.getLastCellNum()]; for (int i = 0; i < sourceRow.getLastCellNum(); i++) { if (sourceRow.getCell(i) != null && sourceRow.getCell(i).getCellType() == Cell.CELL_TYPE_FORMULA) formulasArray[i] = sourceRow.getCell(i).getCellFormula(); } worksheet.shiftRows(rowNum, worksheet.getLastRowNum(), 1); Row newRow = sourceRow; //Now sourceRow is the empty line, so let's rename it sourceRow = worksheet.getRow(rowNum + 1); //Now the source row is at rowNum+1 // Loop through source columns to add to new row for (int i = 0; i < sourceRow.getLastCellNum(); i++) { // Grab a copy of the old/new cell Cell oldCell = sourceRow.getCell(i); Cell newCell; // If the old cell is null jump to next cell if (oldCell == null) { continue; } else { newCell = newRow.createCell(i); } // Copy style from old cell and apply to new cell CellStyle newCellStyle = worksheet.getWorkbook().createCellStyle(); newCellStyle.cloneStyleFrom(oldCell.getCellStyle()); newCell.setCellStyle(newCellStyle); // If there is a cell comment, copy if (oldCell.getCellComment() != null) { newCell.setCellComment(oldCell.getCellComment()); } // If there is a cell hyperlink, copy if (oldCell.getHyperlink() != null) { newCell.setHyperlink(oldCell.getHyperlink()); } // Set the cell data type newCell.setCellType(oldCell.getCellType()); // Set the cell data value switch (oldCell.getCellType()) { case Cell.CELL_TYPE_BLANK: break; case Cell.CELL_TYPE_BOOLEAN: newCell.setCellValue(oldCell.getBooleanCellValue()); break; case Cell.CELL_TYPE_ERROR: newCell.setCellErrorValue(oldCell.getErrorCellValue()); break; case Cell.CELL_TYPE_FORMULA: newCell.setCellFormula(formulasArray[i]); break; case Cell.CELL_TYPE_NUMERIC: newCell.setCellValue(oldCell.getNumericCellValue()); break; case Cell.CELL_TYPE_STRING: newCell.setCellValue(oldCell.getRichStringCellValue()); break; default: break; } } // If there are any merged regions in the source row, copy to new row for (int i = 0; i < worksheet.getNumMergedRegions(); i++) { CellRangeAddress cellRangeAddress = worksheet.getMergedRegion(i); if (cellRangeAddress.getFirstRow() == sourceRow.getRowNum()) { CellRangeAddress newCellRangeAddress = new CellRangeAddress(newRow.getRowNum(), (newRow.getRowNum() + (cellRangeAddress.getLastRow() - cellRangeAddress.getFirstRow() )), cellRangeAddress.getFirstColumn(), cellRangeAddress.getLastColumn()); worksheet.addMergedRegion(newCellRangeAddress); } } }
我在生产代码中使用这个实现。
我最近遇到同样的问题。 我不得不在隐藏行的文档中插入新行,并面临同样的问题。 在apache poi列表中进行了一些search和一些电子邮件之后,当文档隐藏行时,它看起来像shiftrows()中的一个bug。
引用Qwerty的答案 ,如果destRow不为null,sheet.shiftRows()将把destRow的引用改为下一行; 所以我们应该总是创造一个新的行:
if (destRow != null) { sheet.shiftRows(destination, sheet.getLastRowNum(), 1); } destRow = sheet.createRow(destination);