当前位置: 首页 > 知识库问答 >
问题:

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

金令秋
2023-03-14

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

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

这个SO问题与此类似,提出的解决方案是增加VM的已分配/最大内存。

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

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

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


共有3个答案

越星晖
2023-03-14

Apache POI、HSSF和XSSF中的Excel支持支持3种不同的模式。

一种是完整的、类似DOM的内存“UserModel”,它支持读写。使用通用的SS(电子表格)接口,您可以基本透明地为HSSF(.xls)和XSSF(.xlsx)编码。然而,它需要大量内存。

POI还支持流式只读方式来处理文件,即EventModel。这比UserModel低得多,并且使您非常接近文件格式。对于HSSF(.xls),您可以获得一个记录流,还可以获得一些处理这些记录的帮助(缺少单元格、格式跟踪等)。对于XSSF(.xlsx),您可以从文件的不同部分获得SAX事件流,这有助于获得文件的正确部分,还可以轻松处理文件的常见但很小的位。

仅对于XSSF(.xlsx),POI还支持只写流式写入,适合低级别但低内存的写入。不过,它基本上只支持新文件(某些类型的附加是可能的)。没有等价的HSSF,而且由于在许多记录中来回的字节偏移量和索引偏移量,所以很难做到。。。

对于您的具体情况,正如您在澄清性评论中所描述的,我认为您应该使用XSSF EventModel代码。请参阅POI文档以开始,然后尝试查看POI和Tika中使用它的这三个类以了解更多详细信息。

谢志文
2023-03-14

通过使用文件而不是流,可以提高内存使用率。(最好使用流式API,但流式API有局限性,请参阅http://poi.apache.org/spreadsheet/index.html)

因此

Workbook workbook = WorkbookFactory.create(inputStream);

Workbook workbook = WorkbookFactory.create(new File("yourfile.xlsx"));

这是根据:http://poi.apache.org/spreadsheet/quick-guide.html#FileInputStream

文件与InputStreams

“打开工作簿时,无论是. xls HSSFWorkbook还是. xlsx XSSFWorkbook,都可以从文件或InputStream加载工作簿。使用File对象可以降低内存消耗,而InputStream需要更多内存,因为它必须缓冲整个文件。”

满俊楠
2023-03-14

我在Web服务器环境中也遇到了类似的情况。上载的典型大小约为150k行,如果从一个请求中消耗大量内存,那就不太好了。Apache POI流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工作表的结构方式,并非所有数据都可以在流的当前窗口中使用。但是,如果您只是尝试从单元格中读取简单数据,它可以很好地工作。

 类似资料:
  • 来自https://pypi.org/project/tqdm/: 我获取了这段代码并对其进行了编辑,以便从load_excel创建数据帧,而不是使用随机数: 这给了我一个错误,所以我将df.progress_apply改为: 这是最终代码: 这会产生一个进度条,但它实际上并不显示任何进度,而是加载进度条,当操作完成时,它会跳到100%,从而达到目的。 我的问题是:如何让这个进度条工作? prog

  • 我在用图书馆 我在努力 库,但无法将其转换为工作簿 注意:在最终结果中,我希望返回XSSFWorkbook 上面的代码会内存溢出,任何帮助都将提前感谢

  • 在mac osx环境中使用Apache POI 3.8读取文件时,由于无法加载xlsx文件,因此在Windows中使用Open XML SDK 2.0 for Microsoft Office创建了一个文件。下面是堆栈跟踪。我可以打开文件并查看它。 同样的代码适用于我在mac os环境中创建的文件。如果我在处理之前打开并保存文件,我不会有任何问题。注意:保存后文件大小增加。是在.NET中生成文件并

  • 问题内容: 我正在导入一个 长为1700万数字 的大型文本文件,并且正在使用以下代码: 它会立即加载文件并打印出来,但是要花费很长时间(大约一个小时)才能将转换为,我可以做些什么来加快速度并快速加载数字吗? 问题答案: 作为一种优化,因为是,你可以把它保存到一个 二进制文件 一次,并且加速您的装载增色不少。 加载序列化的对象应该比每次解析一个巨大的字符串都要 快 。 使用以节省你的大整数读回。

  • 我正在写一个程序,它需要从excel文件中读取和写入数据,而不考虑格式(xls或xlsx)。 我知道ApachePOI,但它似乎有不同的类来处理xls文件(HSSF)和xlsx(XSSF)文件。 任何人都知道我将如何实现我在这里的目标。(也欢迎使用POI以外的API的想法)。

  • 代码https://play.golang.org/p/CUEqjsJq5c 错误: 文件大小811字节(用于测试加密自源文件)。我想加密一些更大的文件,1。。500 mb。我可以用RSA来做吗?或者需要使用其他方法吗?