我有一个包含1,300,000条记录的数组。每条记录本身就是一个数组。我读取了数组的每个记录,并将该记录的每个桶插入excel表格的一行单元格中,最后,我将那个excell表格写入excel文件。写完100k的记录后,它变得越来越慢,然后在最后打破。 我使用POI apache来做这个,这是我的代码,我不确定是什么原因导致写入过程减慢了很多。任何提示?
try {
//save to excel file
FileOutputStream out = new FileOutputStream(new File(path));
XSSFWorkbook resultWorkBook = new XSSFWorkbook();
XSSFSheet sheet = resultWorkBook.createSheet("Comparison_result");
int sizeOfOriginalTermMain = 0;
int sizeOfOriginalTermMatch = 0;
//blue cell style
CellStyle blueStyle = resultWorkBook.createCellStyle();
XSSFFont cellFont = resultWorkBook.createFont();
cellFont.setColor(IndexedColors.BLUE.getIndex());
blueStyle.setFont(cellFont);
//yellow bg cell style
CellStyle GreenStyle = resultWorkBook.createCellStyle();
GreenStyle.setFillBackgroundColor(IndexedColors.GREEN.getIndex());
//create heading
Row heading = sheet.createRow(0);
heading.createCell(0).setCellValue("Main List ID");
heading.createCell(1).setCellValue("Match number > 0");
heading.createCell(2).setCellValue("Found Match ID");
heading.createCell(3).setCellValue("Source list: 2");
heading.createCell(4).setCellValue("Matched Trems");
for(int i=0; i<5;i++) {
CellStyle styleRowHeading = resultWorkBook.createCellStyle();
XSSFFont font = resultWorkBook.createFont();
font.setBold(true);
font.setFontName(XSSFFont.DEFAULT_FONT_NAME);
font.setFontHeightInPoints((short)11);
styleRowHeading.setFont(font);
heading.getCell(i).setCellStyle(styleRowHeading);
}
ArrayList<Object> currentList = new ArrayList<Object>();
RecordId mainRecordId = new RecordId();
String mainRecordIdValue = "";
LinkedHashSet<String> commonStrings = new LinkedHashSet<String>();
int numberOfMatch=0;
RecordId matchRecordId = new RecordId();
String matchRecordIdValue = "";
int size = processResult.size();
int matchRecordIdListNumber = 0;
String concatenatedMatchTerms = "";
ArrayList<String> OrininalTemrsInMainList = new ArrayList<String>();
ArrayList<String> OrininalTemrsInMatchList = new ArrayList<String>();
//adding value to each row of the excel sheet
int q= 0;
for (int i = 0; i < size; i++) {
currentList = processResult.get(i);
Row row = sheet.createRow(i+1);
//object ppmsID column
Cell mainIdCell = row.createCell(0);
mainRecordId = (RecordId)(currentList.get(0));
mainRecordIdValue = mainRecordId.getIdValue();
mainIdCell.setCellValue(mainRecordIdValue);
mainIdCell.setCellStyle(blueStyle);
//productDB column
Cell matchNumberCell = row.createCell(1);
commonStrings = (LinkedHashSet<String>)(currentList.get(2));
numberOfMatch = commonStrings.size();
matchNumberCell.setCellValue(Integer.toString(numberOfMatch));
//match record Id
Cell matchIdCell = row.createCell(2);
matchRecordId = (RecordId)(currentList.get(1));
matchRecordIdValue = matchRecordId.getIdValue();
matchRecordIdListNumber = matchRecordId.getListNumber();
matchIdCell.setCellValue(matchRecordIdValue);
Cell sourceListNumber = row.createCell(3);
sourceListNumber.setCellValue(Integer.toString(matchRecordIdListNumber));
//terms of match
Cell matchTerms = row.createCell(4);
concatenatedMatchTerms = getConcatenatedStringFromList(commonStrings);
matchTerms.setCellValue(concatenatedMatchTerms);
OrininalTemrsInMainList = (ArrayList<String>) currentList.get(3);
sizeOfOriginalTermMain = OrininalTemrsInMainList.size();
OrininalTemrsInMatchList = (ArrayList<String>) currentList.get(4);
sizeOfOriginalTermMatch = OrininalTemrsInMatchList.size();
for (int k = 0; k<sizeOfOriginalTermMain;k++) {
Cell newCell = row.createCell(5+k);
newCell.setCellValue(OrininalTemrsInMainList.get(k));
newCell.setCellStyle(blueStyle);
}
Cell emptyCell = row.createCell(5+sizeOfOriginalTermMain);
emptyCell.setCellValue("emptyCell");
emptyCell.setCellStyle(GreenStyle);
for (int n = 0; n<OrininalTemrsInMatchList.size();n++) {
Cell newCell = row.createCell(5+sizeOfOriginalTermMain+1+n);
newCell.setCellValue(OrininalTemrsInMatchList.get(n));
}
}
resultWorkBook.write(out);
out.close();
resultWorkBook.close();
}catch(Exception e) {
System.out.println(e.getMessage());
}
答案 0 :(得分:8)
请勿使用XSSF
创建包含如此多单元格的电子表格
XSSF
依赖于消耗大量内存的对象。
而是使用作为Streaming Usermodel API的SXSSF
。
SXSSF(包:org.apache.poi.xssf.streaming)是API兼容的 在非常大的电子表格中使用XSSF的流扩展 必须生产,堆空间有限。 SXSSF实现了低价 通过限制对a内的行的访问来限制内存占用 滑动窗口,而XSSF可以访问文档中的所有行。 不再在窗口中的旧行变得无法访问,如 它们被写入磁盘。
更新使用XSSF
使用SXSSF
的代码相当简单。
两件重要的事情:
窗口大小(内存中可访问的行数):使用默认值或明确配置(如果合适)
您可以通过new指定工作簿构建时的窗口大小 SXSSFWorkbook(int windowSize)或者您可以通过每张表设置它 SXSSFSheet #setRandomAccessWindowSize(int windowSize)
通过createRow()创建新行时的总数 未刷新的记录将超过指定的窗口大小,然后是行 具有最低索引值的刷新且无法通过访问 getRow()了。
默认窗口大小为100,由SXSSFWorkbook.DEFAULT_WINDOW_SIZE定义。
清理要求
SXSSF分配必须始终清理的临时文件 明确地,通过调用dispose方法。
应该调用:
SXSSFWorkbook.dispose();
所以你应该写一些东西:
SXSSFWorkbook wb = new SXSSFWorkbook(100); // keep 100 rows in memory, exceeding rows will be flushed to disk
// write rows ...
...
// dispose of temporary files backing this workbook on disk
wb.dispose();
关于SXSSF
限制:
由于实现的流媒体性质,有 与XSSF相比,存在以下限制:
某个时间点只能访问有限数量的行。
不支持Sheet.clone()。
不支持公式评估
关于您损坏的文件:
According to official SXSSF
limitations,如果您不依赖于公式评估,则损坏的Excel文件的原因可能与SXSSF
模型无关。
在尝试任何操作之前,您可以更新到最后一个稳定的POI版本。
然后,很难给出具体的指示,但作为一般建议,隔离事物以试图了解到底发生了什么。
您可以首先减少生成的行数并仅处理一些特定的列,以查看是否可以解决问题
如果它不起作用,您还可以使用默认样式进行测试。