处理大的xlsx文件
我需要自动适合大(30k +行)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行不是一个上限。
尝试使用事件API。 有关详细信息,请参阅POI文档中的事件API(仅限HSSF)和XSSF和SAX(事件API) 。 来自该页面的几个引号:
HSSF:
事件API比用户API更新。 它适用于愿意学习一些低级API结构的中级开发人员。 它的使用相对简单,但需要对Excel文件的某些部分有基本的了解(或愿意学习)。 所提供的优点是可以读取内存空间相对较小的XLS。
XSSF:
如果内存占用是一个问题,那么对于XSSF,您可以获取底层的XML数据,并自行处理。 这是针对那些愿意学习一点点低层结构的.xlsx文件的中级开发人员,以及在java中处理XML的人员。 它的使用相对简单,但需要对文件结构有一个基本的了解。 所提供的优点是,您可以读取内存空间相对较小的XLSX文件。
对于输出,在博客文章Streaming xlsx文件中描述了一种可能的方法。 (基本上,使用XSSF生成容器XML文件,然后将实际内容以纯文本的forms传输到xlsx zip归档文件的相应xml部分。)
内存使用情况的显着改善可以通过使用File而不是Stream来完成。 (最好使用stream媒体API,但Streaming 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
文件与InputStreams
“打开工作簿时,无论是.xls HSSFWorkbook还是一个.xlsx XSSFWorkbook,都可以从File或InputStream中加载工作簿。使用File对象可以降低内存消耗,而InputStream则需要更多的内存缓冲整个文件“。
我遇到了同样的问题,行数很less,但是大的string。
由于我不必保留我的数据加载,我发现我可以使用SXSSF而不是XSSF。
他们有相似的接口,这有助于如果你已经写了很多的代码。 但是使用SXSSF,可以设置您保持加载的行数。
如果你想自动适应或设置样式或写大(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");
我使用Event API来处理HSSF文件(.xls),并且发现了关于logging顺序的严重缺乏文档。
这里是我发现的一个例子,将处理非常大的XLSX文件。 我的testing迄今看起来不错。 它能够处理非常大的文件,无内存问题。
如果您正在写入 XLSX,则通过写入同一个Excel文件的不同表单来发现改进。 您也可以通过写入不同的Excel文件来find改进。 但首先尝试写入不同的工作表。
下面的堆栈溢出线程描述了最好的例子: 通过Apache POI读取大型Excel文件(xlsx)时出错
该主题的主要答案中的代码片段说明了围绕SAX xmlparsing的Apache POI包装,以及如何简单地遍历所有表单,然后遍历每个单独的单元格。
由于endRow()api提供了已经完成处理的当前行号,所以代码在当前的Apache POI API实现中是陈旧的。
有了这个代码片段,你应该很容易parsing一个大的XLSX文件逐个单元格。 例如,每张纸; 对于每个行单元格; 行已结束事件。 你可以在你创build一个columneName的map到cellValue的每一行的地方创build应用逻辑。
我有同样的问题,80,000单元格和3M字符XSSF分配1GB的堆!
我用Python和openpyxl
和numpy
来读取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.xlsx的foo.txt文件格式。
我使用SAXparsing器来处理XML结构。 它适用于XLSX文件。