2017-05-17 35 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