2017-05-17 34 views
1

我正在使用Apache Poi XSSFWorkbooks来操作xlsx文件;我的程序在小型Excel文件(60 000行)上正常工作。当我开始在一个大文件(700 000行)上测试我的代码时,我遇到了内存问题。我在16 GB RAM的计算机上测试我的代码,但无法正常工作。Java堆空间错误,我无法在java中处理大型xlsx文件

这个问题的任何帮助?我阅读了SAX解析器,但我不想修改我的代码,而且我也觉得它不直观,它不是简单的,如xssf哪些有简单的方法来获取单元格,行..等

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

+4

尝试增加堆大小:问题: http://stackoverflow.com/questions/1565388/increase-heap-size-in-java –

+0

因为SAX是一个很好的解决方案,你不要不想使用它,csv格式可以是很好的选择,CSV格式可以通过Excel打开,很好的理由是考虑使用可以流式处理的格式,而不是一次读入内存。将内容类型设置为application/vnd.ms-excel和扩展类型“.xls”。 –

回答

3

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

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

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

文件大小/内存使用

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

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

而且

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

  • 我认为POI占用了太多的记忆!我能做什么?这一个出现了很多,但通常原因并不是你可能最初想到的。所以,首先要检查的是 - 问题的来源是什么 ?你的文件?你的代码?你的环境?还是Apache POI?
  • (如果你在这里,你可能认为这是Apache的POI。然而,经常 是不是!适度的笔记本电脑,一个体面的,但不能过度堆大小, 从起步,能够正常在几秒钟内读取或写入包含100列和100000行的文件,包括启动JVM的 时间。

    Apache POI附带一些程序和一些示例程序,可用于执行一些基本的性能检查。对于测试文件 的生成,要使用的类位于示例包中, SSPerformanceTest(viewvc)。运行SSPerformanceTest,参数为 写入类型(HSSF,XSSF或SXSSF),数字行,列数 ,以及是否应保存文件。如果在3秒内无法通过 在HSSF和SXSSF中以50,000行和50列运行,并且在10秒内(并且理想情况下所有3个都小于!),则 问题与您的环境有关。

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

    而且

    文件VS 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")); 
    

    如果直接使用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(); 
    
    +0

    非常好,并解释答案。感谢您的时间,写下这个和+1。即使我为我的应用程序学到了一些东西,以提高它! – Nico