将许多记录写入excel文件可能会变得非常慢

时间:2018-01-04 22:58:36

标签: java apache-poi

我有一个包含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());
}

1 个答案:

答案 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版本。

然后,很难给出具体的指示,但作为一般建议,隔离事物以试图了解到底发生了什么。
您可以首先减少生成的行数并仅处理一些特定的列,以查看是否可以解决问题 如果它不起作用,您还可以使用默认样式进行测试。