【问题标题】:Too much memory used when add comments to Excel using Poi SXSSFWorkbook使用 Poi SXSSFWorkbook 向 Excel 添加注释时使用的内存过多
【发布时间】:2017-03-21 08:45:36
【问题描述】:

我的应用程序创建了一个电子表格,它可能相当大(最多 500,000 行,每行分布在六张纸上,每张大约有 20 列)。

我使用 Apache Poi 并转而使用 SXSSFWorkBook 将数据写入临时文件,这样使用的内存与最终电子表格的大小不成比例,这很有效。

但电子表格表示元数据已更改,并且当元数据已更改时,我想向显示旧值的单元格添加注释。我让这个适用于小型电子表格,但在尝试处理大文件时它总是会因堆内存错误而失败。

我不确定问题是由于 Poi 将所有 cmets 存储在内存中的限制,还是我做错了。 Worksheet 是我自己的包装类,我只为每张纸创建一个 DrawingPatriach 类,但看起来我必须为我需要的每条评论创建一个锚。

private void addCellComment(Row r, Cell c, Worksheet sheet, String value)
{
    String formattedValue    =  value.replace('\u0000', '\n');
    int    rowCount         =  value.split("\\\\u000").length;
    ClientAnchor anchor = factory.createClientAnchor();
    anchor.setCol1(c.getColumnIndex());
    anchor.setCol2(c.getColumnIndex()+2);
    anchor.setRow1(r.getRowNum());
    anchor.setRow2(r.getRowNum()+rowCount);

    Drawing drawing = sheet.getDrawing();
    Comment comment = drawing.createCellComment(anchor);
    RichTextString str = factory.createRichTextString(formattedValue);
    comment.setString(str);
    c.setCellComment(comment);
} 

【问题讨论】:

  • 我不知道我们可以如何帮助解决这个问题。在这种情况下,您可能不得不求助于一个非常好的分析器,并且profile您的应用程序以准确了解消耗内存的位置、方式和原因。
  • 需要多少内存?你的java内存设置是什么?你用的是哪个java?您的工作站有多少内存?
  • 我正在寻找具有 Poi 专业知识而不是内存分析专业知识的人。我分配了 1GB 的内存,如果我删除了创建注释部分,我可以创建一个包含 20,000 行的电子表格,并且内存永远不会达到 300mb,但是重新添加 cmets 并且它总是在堆内存上失败。我在 Windows 10 上使用 jre1.8.0_111
  • 请您添加更多代码我想知道您如何初始化 SXSSFWorkbook 窗口大小是多少?您是否关闭了自动刷新并使用手动控制如何将行刷新到磁盘?
  • @SauliusNext 我只是做 workbook = new SXSSFWorkbook(1000) - 我没有关闭刷新,如果我不添加评论单元,那么它使用的内存比我只使用 HSSFWorkbook 少得多。问题特定于评论单元

标签: java apache-poi


【解决方案1】:

好吧,来自Apache POI documentation(强调我的):

请注意,根据您使用的功能,仍有一些东西可能会消耗大量内存,例如合并区域、超链接、cmets...仍然只存储在内存中,因此如果广泛使用可能需要大量内存

所以我猜这是 Apache POI 的限制,您必须解决这个问题。

【讨论】:

  • 很好,好吧,这已经确认了这个问题,我已经提出了一个错误bz.apache.org/bugzilla/show_bug.cgi?id=60894 怀疑是这种情况。我没有的是一种解决方法,我看不到绕过它的方法。
  • 就我个人而言,我会放弃尝试将这些信息保留为 cmets:在 .xlsx 格式中,cmets 被“带外”存储,因此 POI 需要将其保存在内存中,直到每张工作表完成.由于 .xlsx 基本上是一堆压缩的 XML 文件,您还可以考虑生成没有 cmets 的工作簿,然后添加第二个解压缩过程,修改 XML 以添加 cmets 并重新压缩。请点击以下链接了解有关此方法的更多信息:msdn.microsoft.com/en-us/library/office/gg278316.aspxmsdn.microsoft.com/en-us/library/dd979921(v=office.12).aspx
  • 好主意(至少原则上可能需要一些工作)没有意识到它是 xml,考虑到这一点,是否也可以按照 @ChristophBimminger 分阶段保存并重新打开文件并附加在不使用 poi 的情况下读取所有数据,因为那样会更简单
  • 你所说的“带外”是什么意思
  • @PaulTaylor en.wikipedia.org/wiki/Out-of-band_data 在这种情况下,如果您检查 .xlsx,您将看到 cmets 未写入 sheetXXX.xml 文件,而是写入不同的文件,commentXXX.xml。当前的 POI 实现无法将 cmets“流式传输”到该文件,而是保留它们并在工作表完成时一次性写入整个 commentXXX.xml 文件。
猜你喜欢
  • 2018-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-24
  • 2011-11-01
  • 1970-01-01
  • 2015-03-25
  • 1970-01-01
相关资源
最近更新 更多