POI XSSF仍然存在内存问题吗?

11
几年前,我在使用 jXLS 和 POI XSSF 创建大型 Excel 文件时遇到了问题。如果我没记错的话,XSSF 会在磁盘上创建1GB+的临时文件来创建10MB的Excel文件。所以我停止了使用 jXLS,转而使用 SXSSF 来创建 Excel 文件,但今天我有新的理由需要使用 jXLS 或 JETT。
jXLS 和 JETT 网站都暗示性能更好,但POI的 XSSF网站仍然通用地说XSSF需要更高的内存占用。我想知道这种更高的内存占用现在是否像合理的10%开销一样,或者它仍然像几年前那样有着10000%的开销。
POI 3.9 XSSF是否已修复了可怕的内存问题? 我在使用jXLS或JETT时不用担心吗? 还是有某些要避免的陷阱? 我会小心重复使用单元格样式。

1
这个问题感觉非常模糊,但是你可以自己看一下发行版本中都包含了哪些内容:http://poi.apache.org/changes.html。似乎没有得到明确的解决。 - James Kingsbery
无论你做什么,使用“.xlsx”工作需要更多的内存或临时文件比“.xls”,因为所有XML和压缩的开销都高于二进制格式。 - Gagravarr
@James:我不知道如何更加明确。大约10%的开销似乎是合理的,而10,000%的开销则不是。我正在尝试找出内存开销是否仍然像以前一样高达10,000%,还是更接近于10%。 - Bob Thule
@Gagravarr:.xls 格式不支持大型 Excel 文件(仅限于 65,536 行),因此它不是一个选项。此外,使用 XSSFX 的内存占用开销比 HSSF 小,因此 .xlsx 不一定需要比 .xls 更多的内存或临时文件。 - Bob Thule
@James:抱歉,我本意是想说我已经查看了那份变更文档(以及其他很多地方)。我没有找到明确说明内存问题已经解决的内容,但有可能存在逻辑错误导致该问题未在xml或内存中列出。也有可能是jxls中存在的bug导致了这个问题(尽管我听说其他人因与jxls无关的内存问题而放弃了XSSF)。我希望其他人能知道这个内存问题是否已经消失,这样我就不必花费大量时间进行测试了。 - Bob Thule
显示剩余3条评论
1个回答

10
回答您的问题,是的,POI在处理大型XLSX文件时将始终使用非常大量的内存,这比XLSX文件的大小大得多。 我认为这种情况不会很快改变,有很明显的原因:XLSX基本上是一堆压缩的XML文件,而XML可以非常好地压缩(约为10倍)。仅仅让这个XML在内存中不压缩就会使内存消耗增加十倍,所以如果添加所有数据结构的开销,你不应该期望内存消耗只增加了XLSX文件大小的10%。
现在,好消息是,正如评论中提到的那样,Apache POI引入了SXSSF,用于流式传输大量数据,具有非常好的性能和低内存使用率。 以这种方式生成的XLSX文件仍在硬盘上进行流式传输,可能占用相当多的空间,但至少在写入数十万行时不会出现OOME的风险。
你的问题是,JETT无法直接与SXSSF一起使用,因为它需要将整个文档加载到内存中才能执行模板填充。JETT作者在这里快速讨论了这个话题。
我遇到了同样的问题,最终采用了两步XLSX创建方法:
1. 使用标准的JETT XLSX模板生成标题和格式。第一个工作表的最后一行包含$$tokens$$单元格,每个单元格一个。我不使用JETT插入大量的行。 2. JETT完成其工作后,重新打开工作簿,在第一个电子表格的最后一行读取并删除$$tokens$$,然后逐行使用SXSSF流式传输数据。
当然,这种方法有局限性: - 在插入行时不能在任何流式传输的行上使用JETT(但您可以在之前使用它来动态选择$$tokens$$的顺序) - 除非您使用POI API自行处理,否则不会复制单元格格式。我个人更喜欢在我的XLSX文件中格式化整个列,并将其应用于流式传输的数据。
这也适用于使用SXSSF插入数据显示图表的情况:您可以使用OFFSET和COUNTA函数定义一个命名范围,然后创建一个透视表和透视图表,在Excel中打开XLSX时会自动刷新。

1
我不同意POI必须使用大量内存和/或巨大的临时文件。按照你的回答逻辑,那么Excel、OpenOffice和LibreOffice都会遇到相同的内存问题。 - Bob Thule
2
我认为真正的问题在于POI使用了一个糟糕的内部数据结构设计——一般来说,一个XML文件比它的ZIP文件大12倍。在报告生成过程中,POI使用一个临时文件,该文件比生成的XLSX文件大1000倍——因此,这绝对不仅仅是压缩引起的问题。 - Bob Thule
我理解你说的Excel/Office/LibreOffice可以轻松加载大型XLSX文件,但我认为这些软件必须使用优化的内部结构才能有效地存储应用程序中显示的数据。另一方面,POI是一个库,它从XLS格式的接口开始,并保持相同的接口以允许修改基于XML的XLSX格式。保留XML结构的等效形式以进行更改是有意义的,因为写回XLSX格式非常直观,而不是通过优化的数据结构。 - Etienne C

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