Java堆空间错误,我无法在Java中处理大型xlsx文件

Haj*_*r M 1 java xlsx large-files apache-poi

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

这个问题有帮助吗?我读过有关SAX解析器的信息,但是我不想修改我的代码,而且我觉得使用起来并不直观。这不像xssf那样简单,它具有获取单元格,行等的简单方法。

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

Vik*_*ren 5

根据经验,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列的文件并在几秒钟内(包括启动JVM的时间)在10万行之内。

Apache POI附带了一些程序和一些示例程序,可用于进行一些基本的性能检查。为了测试文件生成,要使用的类在示例包SSPerformanceTest(viewvc)中。使用写入类型(HSSF,XSSF或SXSSF)的参数,行数,列数以及是否应保存文件来运行SSPerformanceTest。如果您不能在3秒内在HSSF和SXSSF中运行50,000行50列,而在10秒内运行XSSF(最好是在不到3秒内运行全部!),那么问题就出在您的环境上。

接下来,使用示例程序ToCSV(viewvc)尝试使用HSSF或XSSF读取文件。相关的是XLSX2CSV(viewvc),它对.xlsx使用SAX解析。针对您的问题文件和由SSPerformanceTest生成的相同大小的简单文件运行此文件。如果这很慢,则可能是Apache POI的文件处理方式问题(POI做出了一些假设,这些假设可能并不总是适用于所有文件)。如果这些测试速度很快,那么您的代码中就有性能问题!

文件与InputStreams 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"));
Run Code Online (Sandbox Code Playgroud)

如果直接使用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();
Run Code Online (Sandbox Code Playgroud)