【问题标题】:Java heap space error, I can't process large xlsx file in javaJava堆空间错误,我无法在java中处理大的xlsx文件
【发布时间】:2017-05-17 13:08:49
【问题描述】:

我正在使用 Apache Poi XSSFWorkbooks 来操作 xlsx 文件;我的程序在小型 excel 文件(60 000 行)上运行良好。当我开始在一个大文件(700 000 行)上测试我的代码时,我遇到了内存问题。我在具有 16 GB RAM 的计算机上测试我的代码,但它不起作用。

对这个问题有帮助吗?我阅读了有关 SAX 解析器的信息,但我不想修改我的代码,而且我发现它使用起来并不直观;它不像 xssf 那样简单,它有简单的方法来获取单元格,rows..etc

有没有办法让我的代码保持原样并解决内存问题?或者除了 SAX 解析器之外的任何解决方案?任何帮助表示赞赏,谢谢。

【问题讨论】:

  • 因为 SAX 是一种很好的解决方案并且您不想使用它,所以 csv 格式可以是很好的替代方案,CSV 格式可以通过 Excel 打开,并且有充分的理由考虑使用可以流式传输的格式, 而不是一次全部读入内存。将内容类型设置为 application/vnd.ms-excel 和扩展类型“.xls”。

标签: java apache-poi xlsx large-files


【解决方案1】:

根据经验,SAX 确实对内存性能有很大帮助。从 4GB+ 增加到 300MB 左右。

一些有用的链接和其他提示:

来自https://poi.apache.org/spreadsheet/limitations.html

文件大小/内存使用情况

Excel 文件格式存在一些固有限制。这些都是 在类 SpreadsheetVersion 中定义。只要你有足够的 主内存,您应该能够处理达到这些限制的文件。 对于使用默认 POI 类的大文件,您可能需要一个 非常大的内存量。

如果需要,有一些方法可以克服主存限制:对于 写非常大的文件,有 SXSSFWorkbook 允许做一个 将数据流式写入文件(对什么有一定的限制) 您可以这样做,因为只有部分文件保存在内存中)。用于阅读 非常大的文件,看看示例 XLSX2CSV,它显示了如何 您可以以流方式读取文件(同样有一些限制 你可以从文件中读出哪些信息,但有一些方法 如有必要,最多获得它)。

还有

https://poi.apache.org/faq.html#faq-N10165

  1. 我认为 POI 占用了太多内存!我能做些什么?这个出现了很多,但通常原因不是你可能的 初步认为。所以,首先要检查的是——来源是什么 的问题?你的文件?你的代码?你的环境?还是 Apache POI?

(如果你在这里,你可能会认为它是 Apache POI。然而,它经常 不是!一台中等大小的笔记本电脑,堆大小适中但不过大, 从一开始,可以正常读取或写入 100 个文件 在几秒钟内完成列和 100,000 行,包括 是时候启动 JVM)。

Apache POI 附带了一些程序和一些示例程序,它们 可以用来做一些基本的性能检查。用于测试文件 生成,要使用的类在示例包中, SSPerformanceTest (viewvc)。使用参数运行 SSPerformanceTest 书写类型(HSSF、XSSF 或 SXSSF)、行数、行数 列,以及是否应保存文件。如果你不能运行它 HSSF 和 SXSSF 在 3 秒内完成 50,000 行和 50 列,以及 XSSF 不到 10 秒(理想情况下,所有 3 秒不到!),然后 问题在于您的环境。

接下来,使用示例程序 ToCSV (viewvc) 尝试读取文件 与 HSSF 或 XSSF 一起使用。相关的是使用 SAX 的 XLSX2CSV (viewvc) 解析.xlsx。对您的问题文件和一个 由相同大小的 SSPerformanceTest 生成的简单。如果这是 慢,那么文件的方式可能存在 Apache POI 问题 正在处理(POI 做出一些可能并不总是 正确的所有文件)。如果这些测试很快,那么任何性能 你的代码有问题!

文件与输入流http://poi.apache.org/spreadsheet/quick-guide.html#FileInputStream

When opening a workbook, either a .xls HSSFWorkbook, or a .xlsx XSSFWorkbook, the Workbook can be loaded from either a File or an InputStream. Using a File object allows for lower memory consumption, while an InputStream requires more memory as it has to buffer the whole file.

If using WorkbookFactory, it's very easy to use one or the other:

  // Use a file
  Workbook wb = WorkbookFactory.create(new File("MyExcel.xls"));

  // Use an InputStream, needs more memory
  Workbook wb = WorkbookFactory.create(new FileInputStream("MyExcel.xlsx"));

如果直接使用 HSSFWorkbook 或 XSSFWorkbook,一般应该 通过 NPOIFSFileSystem 或 OPCPackage,可以完全控制 生命周期(包括完成后关闭文件):

  // HSSFWorkbook, File
  NPOIFSFileSystem fs = new NPOIFSFileSystem(new File("file.xls"));
  HSSFWorkbook wb = new HSSFWorkbook(fs.getRoot(), true);
  ....
  fs.close();

  // HSSFWorkbook, InputStream, needs more memory
  NPOIFSFileSystem fs = new NPOIFSFileSystem(myInputStream);
  HSSFWorkbook wb = new HSSFWorkbook(fs.getRoot(), true);

  // XSSFWorkbook, File
  OPCPackage pkg = OPCPackage.open(new File("file.xlsx"));
  XSSFWorkbook wb = new XSSFWorkbook(pkg);
  ....
  pkg.close();

  // XSSFWorkbook, InputStream, needs more memory
  OPCPackage pkg = OPCPackage.open(myInputStream);
  XSSFWorkbook wb = new XSSFWorkbook(pkg);
  ....
  pkg.close();

【讨论】:

  • 非常好和解释答案。感谢您抽出宝贵的时间写这篇文章和 +1。甚至我也学到了一些东西来改进我的应用程序!
猜你喜欢
  • 2012-04-16
  • 1970-01-01
  • 2013-06-28
  • 2015-01-23
  • 2023-04-07
  • 1970-01-01
  • 2013-05-03
  • 1970-01-01
相关资源
最近更新 更多