您好我正在使用Apache POI 3.11
我尝试将大约50,000行的数据写入现有的xlsx文件中。我的表现很慢(约3分钟)。所以我决定使用这里所述的SSPerformanceTest https://poi.apache.org/faq.html#faq-N10165
I discovered that the slowness is from calling sheet.createRow(); after sheet.shiftRow();
当我开箱即用SSPerformanceTest测试时,它表现非常好(大约10秒就有50,000行),但经过一些修改以满足我的要求后,它变得非常糟糕。
我需要shiftRow,因为excel文件将包含文件底部的内容,如签名等。
这里的代码很好(有一些调试记录时间已经过去)
private static void addContent(Workbook workBook, boolean isHType, int rows, int cols) {
Map<String, CellStyle> styles = createStyles(workBook);
Sheet sheet = workBook.getSheetAt(0);
long startShiftRow = System.currentTimeMillis();
long endShiftRow = System.currentTimeMillis();
System.out.println("###@@@ Elapsed shift rows " + (endShiftRow - startShiftRow) + " milli seconds");
Cell headerCell = sheet.createRow(0).createCell(0);
headerCell.setCellValue("Header text is spanned across multiple cells");
headerCell.setCellStyle(styles.get("header"));
sheet.addMergedRegion(CellRangeAddress.valueOf("$A$1:$F$1"));
int sheetNo = 0;
int rowIndexInSheet = 1;
double value = 0;
Calendar calendar = Calendar.getInstance();
double totalCreateRowTime = 0;
double totalSetValue = 0;
for (int rowIndex = 0; rowIndex < rows; rowIndex++) {
if (isHType && sheetNo != rowIndex / 0x10000) {
sheet = workBook.createSheet("Spillover from sheet " + (++sheetNo));
headerCell.setCellValue("Header text is spanned across multiple cells");
headerCell.setCellStyle(styles.get("header"));
sheet.addMergedRegion(CellRangeAddress.valueOf("$A$1:$F$1"));
rowIndexInSheet = 1;
}
long startCreateRow = System.currentTimeMillis();
Row row = sheet.createRow(rowIndexInSheet);
long endCreateRow = System.currentTimeMillis();
totalCreateRowTime += endCreateRow - startCreateRow;
long startSetValue = System.currentTimeMillis();
for (int colIndex = 0; colIndex < cols; colIndex++) {
value = populateCell(styles, value, calendar, rowIndex, row, colIndex);
}
long endSetValue = System.currentTimeMillis();
totalSetValue += endSetValue - startSetValue;
rowIndexInSheet++;
}
System.out.println("###@@@ Elapsed average create row " + (totalCreateRowTime / rows) + " milli seconds");
System.out.println("###@@@ Elapsed average set value " + (totalSetValue / rows) + " milli seconds");
}
然后我添加了移位行
private static void addContent(Workbook workBook, boolean isHType, int rows, int cols) {
Map<String, CellStyle> styles = createStyles(workBook);
Sheet sheet = workBook.getSheetAt(0);
long startShiftRow = System.currentTimeMillis();
sheet.shiftRows(0, sheet.getLastRowNum(), rows); // I ADD IT HERE, ONLY 1 LINE !!!
long endShiftRow = System.currentTimeMillis();
System.out.println("###@@@ Elapsed shift rows " + (endShiftRow - startShiftRow) + " milli seconds");
Cell headerCell = sheet.createRow(0).createCell(0);
headerCell.setCellValue("Header text is spanned across multiple cells");
headerCell.setCellStyle(styles.get("header"));
sheet.addMergedRegion(CellRangeAddress.valueOf("$A$1:$F$1"));
int sheetNo = 0;
int rowIndexInSheet = 1;
double value = 0;
Calendar calendar = Calendar.getInstance();
double totalCreateRowTime = 0;
double totalSetValue = 0;
for (int rowIndex = 0; rowIndex < rows; rowIndex++) {
if (isHType && sheetNo != rowIndex / 0x10000) {
sheet = workBook.createSheet("Spillover from sheet " + (++sheetNo));
headerCell.setCellValue("Header text is spanned across multiple cells");
headerCell.setCellStyle(styles.get("header"));
sheet.addMergedRegion(CellRangeAddress.valueOf("$A$1:$F$1"));
rowIndexInSheet = 1;
}
long startCreateRow = System.currentTimeMillis();
Row row = sheet.createRow(rowIndexInSheet);
long endCreateRow = System.currentTimeMillis();
totalCreateRowTime += endCreateRow - startCreateRow;
long startSetValue = System.currentTimeMillis();
for (int colIndex = 0; colIndex < cols; colIndex++) {
value = populateCell(styles, value, calendar, rowIndex, row, colIndex);
}
long endSetValue = System.currentTimeMillis();
totalSetValue += endSetValue - startSetValue;
rowIndexInSheet++;
}
System.out.println("###@@@ Elapsed average create row " + (totalCreateRowTime / rows) + " milli seconds");
System.out.println("###@@@ Elapsed average set value " + (totalSetValue / rows) + " milli seconds");
}
日志结果如下
-- before add shift row --
###@@@ Elapsed shift rows 0 milli seconds
###@@@ Elapsed average create row 0.00442 milli seconds
###@@@ Elapsed average set value 0.19238 milli seconds
###@@@ Elapsed done 14224 milli seconds
-- after add shift row --
###@@@ Elapsed shift rows 139 milli seconds
###@@@ Elapsed average create row 2.93634 milli seconds
###@@@ Elapsed average set value 0.21966 milli seconds
###@@@ Elapsed done 165080 milli seconds
慢速当然不是来自shiftRow本身,因为它只消耗139毫秒。但是,sheet.shiftRow()之后用于sheet.createRow()的时间从0.0044毫秒增加到2.9毫秒超过500次。并且我认为我需要在xlsx文件中写入大约150,000行,这将花费不可接受的时间来处理。
任何其他代码,您可以方便地查看https://svn.apache.org/repos/asf/poi/trunk/src/examples/src/org/apache/poi/ss/examples/SSPerformanceTest.java或直接询问我。
你知道为什么在调用sheet.shiftRow()后,sheet.createRow()会变得很慢吗?有什么我做错了或有任何解决方法吗?提前谢谢。
=============================================== ==============
编辑1
经过多一点调查,替换了sheet.shiftRow();与
sheet.createRow(50005);
足以使整个事情变得缓慢。
答案 0 :(得分:0)
经过一些思考和实验,我找到了问题的原因和解决方法。
<强>原因强>
当我将行移到50000时,它会使excel文件变得太大。即使第1行到第50000行为空,对太大文件的处理也会变得很慢。
<强>解决方案强>
我将那些想要转移到临时表的行复制,然后正常写入我的50000行记录。之后,我将页脚从临时表中复制回来。所以现在我不需要处理大的excel文件,只需要处理2张小的excel文件。