2011-02-04 104 views
28

我需要自動適應大型(30k +行)xlsx文件中的所有行。處理大型xlsx文件

通過Apache POI下面的代碼工作的小檔案,但出去與OutOfMemoryError上路數:

Workbook workbook = WorkbookFactory.create(inputStream); 
Sheet sheet = workbook.getSheetAt(0); 

for (Row row : sheet) { 
    row.setHeight((short) -1); 
} 

workbook.write(outputStream); 

更新:不幸的是,增加堆大小不是一個選項 - OutOfMemoryError出現在-Xmx1024m和30k行不是上限。

+0

在哪裏運行此代碼?內部應用程序/ Web服務器還是獨立的? – JSS 2011-02-04 12:28:47

+0

我在Tomcat 6.0內部運行它 – miah 2011-02-04 12:48:43

+0

在啓動時分配給Tomcat的默認內存是多少? – JSS 2011-02-04 12:58:18

回答

31

嘗試使用事件API。有關詳細信息,請參閱POI文檔中的Event API (HSSF only)XSSF and SAX (Event API)。一對夫婦從該頁面報價:

HSSF:

The event API is newer than the User API. It is intended for intermediate developers who are willing to learn a little bit of the low level API structures. Its relatively simple to use, but requires a basic understanding of the parts of an Excel file (or willingness to learn). The advantage provided is that you can read an XLS with a relatively small memory footprint.

XSSF:

If memory footprint is an issue, then for XSSF, you can get at the underlying XML data, and process it yourself. This is intended for intermediate developers who are willing to learn a little bit of low level structure of .xlsx files, and who are happy processing XML in java. Its relatively simple to use, but requires a basic understanding of the file structure. The advantage provided is that you can read a XLSX file with a relatively small memory footprint.

對於輸出,一個可能的方法是在博客中描述Streaming xlsx files。 (基本上,使用XSSF生成容器XML文件,然後將實際內容以純文本的形式流入xlsx zip歸檔文件的相應xml部分。)

+1

嗨,我也有閱讀大型Excel文件相同的問題。解決內存問題。我曾見過http://poi.apache.org/spreadsheet/how-to.html#xssf_sax_api,它沒有指定如何讀取excel文件。請幫忙。 – ashishjmeshram 2012-02-20 13:38:36

+0

@Ashish:請將您的請求作爲關於堆棧溢出的單獨問題發佈,並提供更多詳細信息。這樣,其他用戶也可以幫助你。 – markusk 2012-03-06 13:59:05

1

我對HSSF文件(.xls)使用了Event API,並且我發現關於記錄順序的文檔缺乏可靠性。

3

我在和行的少了很多,但大串同樣的問題。

因爲我不必保留我的數據加載,我發現我可以使用SXSSF而不是XSSF。

他們有類似的接口,這有助於如果你有很多已經寫好的代碼。但是通過SXSSF,可以設置您保持加載的行數。

這是鏈接。 http://poi.apache.org/spreadsheet/how-to.html#sxssf

10

通過使用File而不是Stream可以顯着改善內存使用情況。 (這是更好地使用流API,但流API的有限制,請參見http://poi.apache.org/spreadsheet/index.html

所以不是

Workbook workbook = WorkbookFactory.create(inputStream); 

Workbook workbook = WorkbookFactory.create(new File("yourfile.xlsx")); 

這是根據:http://poi.apache.org/spreadsheet/quick-guide.html#FileInputStream

Files vs InputStreams

「打開工作簿時,無論是.xls HSSFWorkbook還是.xlsx XSSFWorkbook,都可以從File或InputStream加載工作簿。使用File對象允許更低的內存消耗,而一個InputStream需要更多的內存,因爲它有緩衝整個文件。」

0

如果你是到XLSX,我發現了一個改善通過寫的不同表你也可以通過寫入不同的Excel文件來找到改進,但首先嚐試寫入不同的表單

2

如果要自動擬合或設置樣式或將大行寫入所有行(30k +行)xlsx文件,使用SXSSFWorkbook.Here是幫助你的示例代碼...

SXSSFWorkbook wb = new SXSSFWorkbook(); 
      SXSSFSheet sheet = (SXSSFSheet) wb.createSheet("writetoexcel"); 
      Font font = wb.createFont(); 
       font.setBoldweight((short) 700); 
       // Create Styles for sheet. 
       XSSFCellStyle Style = (XSSFCellStyle) wb.createCellStyle(); 
       Style.setFillForegroundColor(new XSSFColor(java.awt.Color.LIGHT_GRAY)); 
       Style.setFillPattern(XSSFCellStyle.SOLID_FOREGROUND); 
       Style.setFont(font); 
       //iterating r number of rows 
      for (int r=0;r < 30000; r++) 
      { 
       Row row = sheet.createRow(r); 
       //iterating c number of columns 
       for (int c=0;c < 75; c++) 
       { 
        Cell cell = row.createCell(c); 
        cell.setCellValue("Hello"); 
        cell.setCellStyle(Style); 
       } 
    } 
      FileOutputStream fileOut = new FileOutputStream("E:" + File.separator + "NewTest.xlsx"); 
0

這樣做的最好的例子在下面的堆棧溢出線程描述: Error While Reading Large Excel Files (xlsx) Via Apache POI

在該主題主要答覆的代碼片段說明各地SAX解析XML在Apache POI包裝材料,以及如何在所有平凡循環然後覆蓋每個單獨的單元格。

由於endRow()api提供已完成處理的當前行號,因此當前實現的Apache POI API代碼已過時。

使用該代碼片段,您應該可以輕鬆地逐個解析大型XLSX文件。例如。對於每張紙;對於每個行單元格;行已結束事件。 你可以在你創建一個columneName到cellValue的Map的每一行的地方創建應用程序邏輯。

0

我遇到了800,000個單元格和3M字符的問題,其中XSSF分配1GB的堆!

我用Python openpyxlnumpy來讀取xlsx文件(來自Java代碼)並首先將其轉換爲普通文本。然後我用java加載文本文件。它似乎有很大的開銷,但確實很快。

的Python腳本看起來像

import openpyxl as px 
import numpy as np 

# xlsx file is given through command line foo.xlsx 
fname = sys.argv[1] 
W = px.load_workbook(fname, read_only = True) 
p = W.get_sheet_by_name(name = 'Sheet1') 

a=[] 
# number of rows and columns 
m = p.max_row 
n = p.max_column 

for row in p.iter_rows(): 
    for k in row: 
     a.append(k.value) 

# convert list a to matrix (for example maxRows*maxColumns) 
aa= np.resize(a, [m, n]) 

# output file is also given in the command line foo.txt 
oname = sys.argv[2] 
print (oname) 
file = open(oname,"w") 
mm = m-1 
for i in range(mm): 
    for j in range(n): 
     file.write("%s " %aa[i,j] ) 
    file.write ("\n") 

# to prevent extra newline in the text file 
for j in range(n): 
    file.write("%s " %aa[m-1,j]) 

file.close() 

然後在我的Java代碼,我寫了

try { 
    // `pwd`\python_script foo.xlsx foo.txt 
    String pythonScript = System.getProperty("user.dir") + "\\exread.py "; 
    String cmdline = "python " + pythonScript + 
        workingDirectoryPath + "\\" + fullFileName + " " + 
        workingDirectoryPath + "\\" + shortFileName + ".txt"; 
    Process p = Runtime.getRuntime().exec(cmdline); 
    int exitCode = p.waitFor(); 
    if (exitCode != 0) { 
    throw new IOException("Python command exited with " + exitCode); 
    } 
} catch (IOException e) { 
    System.out.println(e.getMessage()); 
} catch (InterruptedException e) { 
    ReadInfo.append(e.getMessage()); 
} 

之後,你會得到foo.txt的這類似於foo.xlsx,但在文本格式。