2016-02-26 151 views
0

我正在進行的項目正在嘗試讀取一個非常大的Excel文件(幾百列和大約3000行)並識別一系列字母中的模式。它在小文件上工作得很好,但是當我嘗試使用這個文件運行它時,即使我只試圖分析前幾行,我也會收到java.lang.OutOfMemoryError: Java heap space錯誤。錯誤似乎是在Workbook wb = WorkbookFactory.create(new File(filepath));在Apache POI中讀取10 MB文件

我已經試過了幾本網站上的解決方案,但在任何成功都不會來。我的代碼如下:

import java.awt.List; 
import java.io.File; 
import java.io.FileInputStream; 
import java.io.IOException; 
import java.util.ArrayList; 

import org.apache.poi.EncryptedDocumentException; 
import org.apache.poi.openxml4j.exceptions.InvalidFormatException; 
import org.apache.poi.ss.usermodel.Workbook; 
import org.apache.poi.ss.usermodel.WorkbookFactory; 
import org.apache.poi.xssf.usermodel.XSSFCell; 
import org.apache.poi.xssf.usermodel.XSSFRow; 
import org.apache.poi.xssf.usermodel.XSSFSheet; 
import org.apache.poi.xssf.usermodel.XSSFWorkbook; 

public class ExcelReader { 

    public int Reader(File file) throws IOException, EncryptedDocumentException, InvalidFormatException { 
     String filepath = file.getPath(); 
     Workbook wb = WorkbookFactory.create(new File(filepath)); 
     XSSFSheet sheet = (XSSFSheet) wb.getSheetAt(0); 
     XSSFRow row; 
     XSSFCell cell; 
     ArrayList<Integer> list = new ArrayList<Integer>(); 

     int rows; 
     int cols = 0; 
     int temp = 0; 
     rows = sheet.getPhysicalNumberOfRows(); 

     for (int i = 0; i <= 1; i++) { 
      row = sheet.getRow(i); 
      if (row != null) { 
       temp = sheet.getRow(i).getPhysicalNumberOfCells(); 
       if (temp > cols) 
        cols = temp; 
      } 
     } 
     for (int r = 0; r <= 60; r++) { 
      row = sheet.getRow(r); 
      if (row != null) { 
       for (int c = 0; c <= cols; c++) { 
        int numblanks = 0; 
        cell = row.getCell((short) c); 
        if (cell != null) { 
         //System.out.print(cell + "\t\t"); 
        } else { 
         //System.out.print("\t\t"); 
        } 
        if (cell != null && cell.getCellType() == XSSFCell.CELL_TYPE_STRING) { 
         if ("N".equals(cell.getStringCellValue())) { 
          for (int k = c; k <= cols; k++) { 
           if ("-".equals(row.getCell(k).getStringCellValue())) { 
            numblanks++; 
            continue; 
           } 
           if ("S".equals(row.getCell(c + 2 + numblanks).getStringCellValue()) 
             || "T".equals(row.getCell(c + 2 + numblanks).getStringCellValue())) { 
            list.add((int) sheet.getRow(1).getCell(c).getNumericCellValue()); 
            break; 
           } 
          } 
         } 
        } 
       } 
       System.out.println(); 
      } 
     } 
     System.out.println(); 
     System.out.println("Rows: " + rows); 
     System.out.println("Columns: " + cols); 
     System.out.println(list); 
     return temp; 
    } 
} 

謝謝任何​​幫助,你可以給我!

+3

你增加與-Xmx最大堆大小?你試過什麼解決方案? – rgettman

+0

你可以編輯你的eclipse配置文件來配置更多內存 – andrewdleach

+0

相關問題: http://stackoverflow.com/questions/1596009/java-lang-outofmemoryerror-java-heap-space –

回答

1

我以前解決過這個問題。我的情況是讀取一個包含23萬行的23M Excel文件。

增加最大堆大小不是一個好的解決方案。 Apache poi沒有流模式來讀取數據。這種非流模式會花費太多內存。

我的解決辦法是將數據轉換爲XML,然後使用XMLReader的解析數據。

請檢查下面的示例代碼:

protected List<Entity> parseData(InputStream in) throws Exception { 
     OPCPackage pkg = OPCPackage.open(in); 
     XSSFReader r = new XSSFReader(pkg); 
     SharedStringsTable sst = r.getSharedStringsTable(); 
     XMLReader parser = fetchSheetParser(sst); 
     XSSFReader.SheetIterator sheets = (XSSFReader.SheetIterator) r.getSheetsData(); 

     while (sheets.hasNext()) { 
      InputStream sheet = sheets.next(); 
      InputSource sheetSource = new InputSource(sheet); 
      parser.parse(sheetSource); 
      sheet.close(); 
      break; // if only need to process one sheet. 
     } 
     return SheetHandler.getRawData(); 
    } 

    private XMLReader fetchSheetParser(SharedStringsTable sst) throws SAXException { 
     XMLReader parser = 
       XMLReaderFactory.createXMLReader(); 
     ContentHandler handler = new SheetHandler(sst); 
     parser.setContentHandler(handler); 
     return parser; 
    } 

    private static class SheetHandler extends DefaultHandler { 

     private SharedStringsTable sst; 
     private String lastContents; 
     private boolean nextIsString; 
     private boolean nextIsInlineString; 
     private boolean nextIsNull; 

     private SheetHandler(SharedStringsTable sst) { 
      this.sst = sst; 
      rawData = new ArrayList<Entity>(); 
     } 

     public static List<Entity> getRawData() { 
      return rawData; 
     } 


     @Override 
     public void startElement(String uri, String localName, String name, 
           Attributes attributes) throws SAXException { 

     } 

     @Override 
     public void endElement(String uri, String localName, String name) 
       throws SAXException { 


     } 

     @Override 
     public void characters(char[] ch, int start, int length) 
       throws SAXException { 
      lastContents += new String(ch, start, length); 
     } 
    } 
} 
+3

Apache的POI確實有一個半容易流模式 - 用[XSSFReader](https://poi.apache.org/apidocs/org/apache/poi/xssf/eventusermodel/XSSFReader.html)和[SheetContentsHandler](HTTPS: //poi.apache.org/apidocs/org/apache/poi/xssf/eventusermodel/XSSFSheetXMLHandler.SheetContentsHandler.html) – Gagravarr

相關問題