java - 如何使用 Apache POI 加载大型 xlsx 文件?

标签 java memory apache-poi out-of-memory xssf

我有一个大的 .xlsx 文件(141 MB,包含 293413 行,每行 62 列)我需要在其中执行一些操作。

我在加载此文件时遇到问题 (OutOfMemoryError),因为 POI 在 XSSF (xlsx) 工作簿上占用了大量内存。

This SO question类似,提出的解决方案是增加VM的分配/最大内存。

它似乎适用于那种文件大小(9MB),但对我来说,即使分配了所有可用的系统内存,它也根本不起作用。 (好吧,考虑到文件大 15 倍以上,这并不奇怪)

我想知道是否有任何方法可以以一种不会消耗所有内存的方式加载工作簿,并且无需进行基于(进入)XSSF 底层 XML 的处理。 (换句话说,保持一个清教徒的 POI 解决方案)

如果没有困难,欢迎您说出来(“没有。”)并指出“XML”解决方案的方法。

最佳答案

我在网络服务器环境中遇到了类似的情况。上传的典型大小约为 150k 行,从单个请求中消耗大量内存并不是一件好事。 Apache POI Streaming API 可以很好地解决这个问题,但它需要对您的读取逻辑进行全面重新设计。我已经有一堆使用标准 API 的读取逻辑,我不想重做,所以我写了这个:https://github.com/monitorjbl/excel-streaming-reader

它并不完全是标准 XSSFWorkbook 类的替代品,但如果您只是迭代行,它的行为类似:

import com.monitorjbl.xlsx.StreamingReader;

InputStream is = new FileInputStream(new File("/path/to/workbook.xlsx"));
StreamingReader reader = StreamingReader.builder()
        .rowCacheSize(100)    // number of rows to keep in memory (defaults to 10)
        .bufferSize(4096)     // buffer size to use when reading InputStream to file (defaults to 1024)
        .sheetIndex(0)        // index of sheet to use (defaults to 0)
        .read(is);            // InputStream or File for XLSX file (required)

for (Row r : reader) {
  for (Cell c : r) {
    System.out.println(c.getStringCellValue());
  }
}     

使用它有一些注意事项;由于 XLSX 工作表的结构方式,并非所有数据都在流的当前窗口中可用。但是,如果您只是想从单元格中读取简单的数据,则效果很好。

关于java - 如何使用 Apache POI 加载大型 xlsx 文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11891851/

相关文章:

java - 使用 Apache POI 将结果集转为 Excel (*.xlsx) 表格

java - Quartz NotSerializedException 异常

java - Spring @Transactional 不适用于 mysql 函数调用

python - dict pop 不释放内存

android - 11223056 字节分配内存不足

java - Java计算Excel某列重复行数

java - OpenOLAT .properties 中的 PayPal 集成

java - java中动态设置类实例变量

javascript - javascript/html:替换嵌入式视频的内存泄漏?

java - 在 XWPFDocument 的任意位置插入 XWPFParagraph