2012-10-22 43 views
7

Sto cercando di leggere file excel di grandi dimensioni xlsx tramite POI Apache, ad esempio 40-50 MB. Sto uscendo dall'eccezione di memoria. La memoria heap corrente è 3 GB.Errore durante la lettura di file Excel di grandi dimensioni (xlsx) Via Apache POI

Sono in grado di leggere file Excel più piccoli senza problemi. Ho bisogno di un modo per leggere file excel di grandi dimensioni e poi di restituirli come risposta tramite Spring excel view.

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+ "\""); 


    }  

} 

ho iniziato fuori usando XSSFWorkbook workbook = new XSSFWorkbook(FileInputStream in); ma che era costoso per Apache POI API, quindi commutato OPC pacchetto modo ma ancora lo stesso effetto. Non ho bisogno di analizzare o elaborare il file, basta leggerlo e restituirlo.

+0

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

+1

ho bisogno di un esempio. Cerco sul web ma non riesco a trovare un esempio per la lettura di grandi fogli tramite SXSSF, altrimenti non avrei posto la domanda in primo luogo. – jamesT

+0

@jamesT hai eseguito questa opzione? -Xms1024M -Xmx2048M – chrome

risposta

6

Non si indica se è necessario modificare il foglio di calcolo o meno.

Questo può essere ovvio, ma se non è necessario modificare il foglio di calcolo, non è necessario analizzarlo e riscriverlo, è sufficiente leggere i byte dal file e scrivere byte, come faresti con, diciamo un'immagine, o qualsiasi altro formato binario.

Se è necessario modificare il foglio di calcolo prima di inviarlo all'utente, per quanto ne so, potrebbe essere necessario adottare un approccio diverso.

Ogni libreria di cui sono a conoscenza per la lettura di file Excel in Java legge l'intero foglio di calcolo in memoria, quindi è necessario disporre di 50 MB di memoria disponibile per ogni foglio di lavoro che potrebbe essere elaborato contemporaneamente. Ciò comporta, come altri hanno sottolineato, la regolazione dell'heap disponibile per la VM.

Se è necessario elaborare un numero elevato di fogli di calcolo contemporaneamente e non è possibile allocare memoria sufficiente, considerare l'utilizzo di un formato che può essere trasmesso in streaming, anziché leggere tutto in una volta nella memoria. Il formato CSV può essere aperto da Excel e ho avuto buoni risultati in passato impostando il tipo di contenuto su application/vnd.ms-excel, impostando il nome file dell'allegato su qualcosa che termina con ".xls", ma in realtà restituendo CSV soddisfare. Non ci ho provato in un paio d'anni, quindi YMMV.

+0

Grazie per la risposta. – jamesT

13

Ecco un esempio per leggere un file xls di grandi dimensioni utilizzando parser di sax.

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

Grazie O.C esattamente quello che stavo cercando per elaborare oltre 250k righe. Funziona perfettamente. – Anand

+0

Grazie mille per lo snippet di codice lassù. Il POI di Apache dovrebbe pubblicare nella propria documentazione un esempio come quello sopra per pubblicizzare più facilmente tali API. – 99Sono

+0

@ O.C Grazie mille !! Potresti dire come considerare le celle vuote in excel usando il codice sopra? – user1799214

0

troppo ho affrontato lo stesso problema di OOM durante l'analisi di file xlsx ... dopo due giorni di lotta, ho finalmente scoperto il codice qui sotto che è stato davvero perfetto;

Questo codice è basato su sjxlsx. Legge xlsx e memorizza in un foglio 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

Questo esempio mostra come scrivere in un file excel, la domanda è su come scrivere in un file excel in poi. – user1707141

Problemi correlati