Apache POI Streaming(SXSSF)用于读取

29

我需要读取大型Excel文件并将它们的数据导入我的应用程序。

由于POI占用了大量的堆空间来工作,经常会抛出OutOfMemory错误,我发现有一种流式API可以以串行方式处理Excel数据(而不是完全将文件加载到内存中)

我创建了一个xlsx工作簿,其中包含单个工作表,并在单元格中键入了多个值,然后编写了以下代码来尝试读取它:

public static void main(String[] args) throws Throwable {
    // keep 100 rows in memory, exceeding rows will be flushed to disk
    SXSSFWorkbook wb = new SXSSFWorkbook(new XSSFWorkbook(new FileInputStream("C:\\test\\tst.xlsx")));
    SXSSFSheet sheet = (SXSSFSheet) wb.getSheetAt(0);
    Row row = sheet.getRow(0);
    //row is always null
    while(row.iterator().hasNext()){ //-> NullPointerException
        System.out.println(row.getCell(0).getStringCellValue());
    }
}

然而,尽管能够正确获取其工作表,但始终会带有空的(null)行。

我进行了研究,并在互联网上找到了几个流API的示例,但它们都是关于生成Excel文件,没有一个关于读取现有文件的。

实际上有可能从现有的.xlsx文件中读取数据吗?


你是在使用Eclipse IDE吗? - Rajdeep Paul
如果您想增加堆空间,我有一个解决方案。 - Rajdeep Paul
根据其他相关的stackoverflow问题所述,https://dev59.com/yGcs5IYBdhLWcg3w3Hun,SXSSFWorkBook只支持写入,不支持读取,这就解释了为什么你得到null。 - Raf
哦,对了,有一个虚拟机参数 -Xmx 可以增加堆空间,我已经将其增加到了2GB,但POI无法读取20MB的文件,所以这不可行。不过还是谢谢! - bruno_cw
2
遵循Apache POI网站上记录的方法,并以流式SAX方式进行操作? - Gagravarr
1个回答

42

在更深入的搜索后,我找到了这个:

如果你以前使用过Apache POI读取Excel文件,你可能会注意到它并不是很内存高效。读取整个工作簿会导致严重的内存使用波动,这可能会对服务器造成灾难性影响。

Apache必须读取整个工作簿的原因有很多,但大多数原因都与该库允许您使用随机地址读写有关。如果(仅当)您只想以快速且内存高效的方式读取Excel文件的内容,则可能不需要此功能。不幸的是,POI库中用于读取流式工作簿的唯一方法要求您的代码使用类似SAX的解析器。所有友好的类,如Row和Cell,在该API中都不存在。

此库作为一个包装器,围绕流式API并保留标准POI API的语法。继续阅读以了解它是否适合您。

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)
        .sheetName("sheet1")  // name of sheet to use (overrides sheetIndex)
        .read(is);            // InputStream or File for XLSX file (required)

此外还有SAX事件API,它通过事件读取文档并解析其内容。

如果内存占用是个问题,那么对于XSSF,您可以访问底层的XML数据,并自己处理它。这适用于愿意学习一点.xlsx文件的低级结构并且能够使用Java处理XML的中级开发人员。它相对简单易用,但需要基本的文件结构理解。提供的优势是可以以相对较小的内存占用读取XLSX文件。


1
是的,我也遇到了同样的问题,使用了这个库,它就像魔法一般运作正常。 - rupesh_padhye
1
但是这个库只能处理 .xlsx 文件,我的业务需求需要使用 .xls 文件,而且正如您所说,POI 在处理大型 Excel 文件时会占用大量的内存。你有什么建议吗? - Akhil S Kamath
我看到SXSSF使用流式处理。那么在2021年我们是否仍需要使用这个库呢?我在该项目的GitHub页面上没有找到任何关于SXSSF的提及,这让我想知道这个库是在SXSSF变得流行之前创建的。 (它可能在稍后的时间发布到GitHub上) 我有一个项目正在使用它,但我想减小构建的大小,而这个jar文件及其依赖项是整个包大小中最大的部分。 - Dojo
2
@Dojo SXSSF仅支持写入,不支持读取。 - ThomasMX
是的,我通过实验发现了这一点,后来在官方文档中看到了一条注释。这些接口是通用的,但如果您调用读取方法,则会失败。 - Dojo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接