Java Apache POI更新现有的Excel文件,不使用InputStream。

3
我正在尝试更新现有的Excel文件(xlsx)。像XSSFWorkbook(java.io.File file)XSSFWorkbook(OPCPackage pkg)这样的构造函数以只读模式打开文件,不允许进行修改。因此我必须使用XSSFWorkbook(java.io.InputStream is),但它的内存占用量(JVM内存和Java Heap)太高了。我不能使用VM参数来设置最大内存大小,因为我必须尊重其他并行运行的程序的内存需求。使用SXSSFWorkbook是另一个解决方案,但它本质上是XSSFWorkbook的包装器。与XSSFWorkbook相同的问题仍然存在。我查看了其他SO帖子,但没有找到任何相关的答案。请问有人能帮助我吗?我很满意存储临时文件。

我使用新的SXSSFWorkbook(-1)和SXSSFSheet.flushRows()取得了不错的结果(更低的内存使用),但那是用于创建新文件,而非更新现有文件。我认为你应该尝试使用SXSSFWorkbook。 - Guillaume
1个回答

1
你的问题不够清晰。实际上,问题并不是“如何在不使用InputStream的情况下打开XSSFWorkbook?”,而是“如何减少XSSFWorkbook的内存占用?”答案是:无法减少,就像apache poi现在编程一样。否则,apache poi的开发人员必须很愚蠢,他们特意编写了apache poi来浪费内存。但是,有太多的抽象级别被使用了。所有内容都基于XML。但是,编程库的用户不想被XML所困扰,至少不想使用分成多个文件的ZIP归档文件中的那种XML,这些文件使用特殊关系XML文件链接在一起。因此,在XML之上有ooxml-schemas,一个库,它将单个文件的XML转换为可用的java对象。还有org.apache.poi.openxml4j.opc.*来管理关系。
为了充分利用此功能,所有可用的java对象(工作簿、工作表、行、单元格、图纸、表格、数据透视表、图表等)及其关系必须在内存中准备好以供使用。或者需要使用临时文件将它们从*.xlsx ZIP归档文件中取出并暂时存储它们。在我看来,直接在ZIP文件系统中操作是不可取的,因为这种类型的文件系统的更改行为可能会导致问题。
但是,apache poi没有提供使用临时文件的选项。只有SXSSF在写入新的*.xlsx文件时才使用工作表的临时文件,而不是在读取和更新此类文件时使用。
为了尽可能与二进制BIFF *.xls文件格式兼容,此处添加了另一级别。这是SS和XSSF级别,提供了apache poi的高级类。因此,除了内存中的低级ooxml-schemas类之外,现在还有额外的工作簿、工作表、行、单元格、图纸、表、数据透视表、图表等java对象。
所以...处理大型.xlsx文件时会出现内存不足的情况。;-)
解决方案呢?
为了尽可能地节省内存,您可以解压缩*.xlsx ZIP归档文件,并直接使用其中的XML进行工作。当然,这非常费力,特别是在创建新内容和考虑关系时。我在这里的答案中提供了一些简单的示例。例如:如何在内存有限的情况下修改大型Excel文件如何使用java + poi设置Excel单元格背景颜色
或者编写一个扩展程序来使用临时文件而不是保存在内存中的所有文件,这当然也很费力,并且对于不提供使用临时文件的系统来说具有缺点。

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