处理大型xlsx文件

问题描述:

我需要自动适应大型(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

尝试使用事件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

我对HSSF文件(.xls)使用了Event API,并且我发现关于记录顺序的文档缺乏可靠性。

这是我发现的一个例子,它可以处理非常大的XLSX文件。迄今为止我的测试看起来不错。它能够处理非常大的文件而不存在内存问题。

http://svn.apache.org/repos/asf/poi/trunk/src/examples/src/org/apache/poi/xssf/eventusermodel/XLSX2CSV.java

我在和行的少了很多,但大串同样的问题。

因为我不必保留我的数据加载,我发现我可以使用SXSSF而不是XSSF。

他们有类似的接口,这有助于如果你有很多已经写好的代码。但是通过SXSSF,可以设置您保持加载的行数。

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

通过使用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需要更多的内存,因为它有缓冲整个文件。”

如果你是到XLSX,我发现了一个改善通过写的不同表你也可以通过写入不同的Excel文件来找到改进,但首先尝试写入不同的表单

如果要自动拟合或设置样式或将大行写入所有行(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"); 

这样做的最好的例子在下面的堆栈溢出线程描述: Error While Reading Large Excel Files (xlsx) Via Apache POI

在该主题主要答复的代码片段说明各地SAX解析XML在Apache POI包装材料,以及如何在所有平凡循环然后覆盖每个单独的单元格。

由于endRow()api提供已完成处理的当前行号,因此当前实现的Apache POI API代码已过时。

使用该代码片段,您应该可以轻松地逐个解析大型XLSX文件。例如。对于每张纸;对于每个行单元格;行已结束事件。 你可以在你创建一个columneName到cellValue的Map的每一行的地方创建应用程序逻辑。

我遇到了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,但在文本格式。

我用SAX解析器来处理XML结构。它适用于XLSX文件。

https://*.com/a/44969009/4587961