2012-10-22 158 views
7

我想通過Apache POI讀取大型Excel文件xlsx,比如說40-50 MB。我越來越內存異常。目前的堆內存是3GB。通過Apache POI讀取大型Excel文件(xlsx)時出錯

我可以讀取較小的excel文件,沒有任何問題。我需要一種方式來讀取大型的Excel文件,然後通過Spring excel視圖作爲迴應。

public class FetchExcel extends AbstractView { 


    @Override 
    protected void renderMergedOutputModel(
      Map model, HttpServletRequest request, HttpServletResponse response) 
    throws Exception { 

    String fileName = "SomeExcel.xlsx"; 

    response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); 

    OPCPackage pkg = OPCPackage.open("/someDir/SomeExcel.xlsx"); 

    XSSFWorkbook workbook = new XSSFWorkbook(pkg); 

    ServletOutputStream respOut = response.getOutputStream(); 

    pkg.close(); 
    workbook.write(respOut); 
    respOut.flush(); 

    workbook = null;      

    response.setHeader("Content-disposition", "attachment;filename=\"" +fileName+ "\""); 


    }  

} 

我第一次開始使用關XSSFWorkbook workbook = new XSSFWorkbook(FileInputStream in); 但是這是每Apache的POI API昂貴,所以我切換到OPC包的方式,但還是同樣的效果。我不需要解析或處理文件,只需讀取並返回即可。

+0

嘗試SXSSF http://poi.apache.org/spreadsheet/index.html – Alfabravo

+1

我需要一個示例。我在網上搜索,但找不到一個通過SXSSF閱讀大單的例子,否則首先不會問這個問題。 – jamesT

+0

@jamesT你運行過這個選項嗎? -Xms1024M -Xmx2048M – chrome

回答

6

您沒有提及是否需要修改電子表格。

這可能很明顯,但如果您不需要修改電子表格,那麼您不需要解析它並將其寫回,只需從文件中讀取字節,然後寫出字節,就像你會用圖像或其他任何二進制格式一樣。

如果您確實需要在將電子表格發送給用戶之前進行修改,那麼就我所知,您可能需要採取不同的方法。

我知道讀取Excel中的所有文檔都會將整個電子表格讀入內存,因此您必須爲每個可能同時處理的電子表格提供50MB的內存。正如其他人指出的那樣,這涉及調整虛擬機可用的堆。

如果您需要同時處理大量電子表格並且無法分配足夠的內存,請考慮使用可以流式處理的格式,而不是一次全部讀入內存。 CSV格式可以通過Excel打開,過去我通過將content-type設置爲application/vnd.ms-excel,將附件文件名設置爲以「.xls」結尾的內容,但實際返回CSV內容。我幾年沒有嘗試過,所以YMMV。

+0

感謝您的回答。 – jamesT

13

下面是使用sax解析器讀取大型xls文件的示例。

public void parseExcel(File file) throws IOException { 

     OPCPackage container; 
     try { 
      container = OPCPackage.open(file.getAbsolutePath()); 
      ReadOnlySharedStringsTable strings = new ReadOnlySharedStringsTable(container); 
      XSSFReader xssfReader = new XSSFReader(container); 
      StylesTable styles = xssfReader.getStylesTable(); 
      XSSFReader.SheetIterator iter = (XSSFReader.SheetIterator) xssfReader.getSheetsData(); 
      while (iter.hasNext()) { 
       InputStream stream = iter.next(); 

       processSheet(styles, strings, stream); 
       stream.close(); 
      } 
     } catch (InvalidFormatException e) { 
      e.printStackTrace(); 
     } catch (SAXException e) { 
      e.printStackTrace(); 
     } catch (OpenXML4JException e) { 
      e.printStackTrace(); 
     } 

} 

protected void processSheet(StylesTable styles, ReadOnlySharedStringsTable strings, InputStream sheetInputStream) throws IOException, SAXException { 

     InputSource sheetSource = new InputSource(sheetInputStream); 
     SAXParserFactory saxFactory = SAXParserFactory.newInstance(); 
     try { 
      SAXParser saxParser = saxFactory.newSAXParser(); 
      XMLReader sheetParser = saxParser.getXMLReader(); 
      ContentHandler handler = new XSSFSheetXMLHandler(styles, strings, new SheetContentsHandler() { 

      @Override 
       public void startRow(int rowNum) { 
       } 
       @Override 
       public void endRow() { 
       } 
       @Override 
       public void cell(String cellReference, String formattedValue) { 
       } 
       @Override 
       public void headerFooter(String text, boolean isHeader, String tagName) { 

       } 

      }, 
      false//means result instead of formula 
      ); 
      sheetParser.setContentHandler(handler); 
      sheetParser.parse(sheetSource); 
     } catch (ParserConfigurationException e) { 
      throw new RuntimeException("SAX parser appears to be broken - " + e.getMessage()); 
} 
+0

謝謝O.C正是我想要處理超過250k行的內容。完美的作品。 – Anand

+0

非常感謝那裏的代碼片段。 Apache POI應在其文檔中發佈一個示例,以便更容易地宣傳這些API。 – 99Sono

+0

@ O.C謝謝!你能告訴如何使用上面的代碼來考慮excel中的空白單元嗎? – user1799214

0

我太OOM面臨的同一個問題在解析XLSX文件...鬥爭後兩天,我終於找到了下面的代碼,那真是完美的;

此代碼基於sjxlsx。它讀取xlsx並將其存儲在HSSF表單中。

  [code=java] 
      // read the xlsx file 
     SimpleXLSXWorkbook = new SimpleXLSXWorkbook(new File("C:/test.xlsx")); 

     HSSFWorkbook hsfWorkbook = new HSSFWorkbook(); 

     org.apache.poi.ss.usermodel.Sheet hsfSheet = hsfWorkbook.createSheet(); 

     Sheet sheetToRead = workbook.getSheet(0, false); 

     SheetRowReader reader = sheetToRead.newReader(); 
     Cell[] row; 
     int rowPos = 0; 
     while ((row = reader.readRow()) != null) { 
      org.apache.poi.ss.usermodel.Row hfsRow = hsfSheet.createRow(rowPos); 
      int cellPos = 0; 
      for (Cell cell : row) { 
       if(cell != null){ 
        org.apache.poi.ss.usermodel.Cell hfsCell = hfsRow.createCell(cellPos); 
        hfsCell.setCellType(org.apache.poi.ss.usermodel.Cell.CELL_TYPE_STRING); 
        hfsCell.setCellValue(cell.getValue()); 
       } 
       cellPos++; 
      } 
      rowPos++; 
     } 
     return hsfSheet;[/code] 
+0

這個例子顯示瞭如何寫入excel文件,問題是關於如何寫入poi中的excel文件。 – user1707141

相關問題