我希望使用Java编程写入Excel(.xls MS Excel 2003格式)文件。 Excel输出文件可能包含约200,000行,我计划将其分成数量的床单(由于Excel限制,每张床单64k行)。

我尝试使用Apache POI API,但由于API对象模型,它似乎是存储器。我被迫将单元/表添加到内存中的工作簿对象中,只有添加所有数据后,我才能将工作簿写入文件!这是Apache建议我使用其API编写Excel文件的示例:

Workbook wb = new HSSFWorkbook();
Sheet sheet = wb.createSheet("new sheet");

//Create a row and put some cells in it
Row row = sheet.createRow((short)0);

// Create a cell and put a value in it.
Cell cell = row.createCell(0);
cell.setCellValue(1);

// Write the output to a file
FileOutputStream fileOut = new FileOutputStream("workbook.xls");
wb.write(fileOut);
fileOut.close();

显然,编写〜20k行(每行中有10-20列)给了我可怕的“ java.lang.outofmemoryerror:java heap aper Space”。

我尝试使用XMS和XMX参数为XMS512M和XMX1024来增加JVM初始堆积和最大堆大小。仍然不能将超过150k的行写入文件。

我正在寻找一种流式传输到Excel文件的方法,而不是在将其写入磁盘之前将整个文件构建到内存中,这将保存大量的内存使用情况。任何替代的API或解决方案都将不胜感激,但我仅限于使用Java。谢谢! :)

有帮助吗?

解决方案

所有现有的Java API尝试立即在RAM中构建整个文档。尝试编写一个符合新XSLX文件格式的XML文件。为了让您入门,我建议在Excel中以所需的形式构建一个小文件并保存它。然后打开它并检查结构并更换所需的零件。

维基百科有一个 关于整体格式的好文章.

其他提示

尝试使用 SXSSF 工作簿,这对于大型XLS文档,其构建文件而根本不吃RAM,这是很棒的事情,因为使用Nio

我不得不将文件分为几个Excel文件,以克服堆空间异常。我认为大约有22列的5K行,所以我只是制作了逻辑,以便每5K行都结束文件,启动新文件,然后相应地数字。

在我有20k +行要编写的情况下,我将有4个以上代表数据的不同文件。

看看 HSSF序列化器 来自茧项目。

HSSF序列化器捕获SAX事件,并以Microsoft Excel使用的XLS格式创建电子表格

还有jexcelapi,但它使用更多的内存。我认为您应该创建.csv文件并在Excel中打开它。它使您可以传递大量数据,但是您无法执行任何“ Excel Magic”。

考虑使用CSV格式。这样,您不再受内存的限制 - 孔,也许只有在预先处理CSV的数据期间,但这也可以有效地完成,例如,从DB中查询行的行子集,例如 LIMIT/OFFSET 并立即将其写入文件,而不是在编写任何行之前将整个DB表内容拖到Java的内存中。一个“工作表”中的数量行的Excel限制将增加到约100万。

也就是说,如果数据实际上来自数据库,那么如果Java是正确的工具,我将高度重新考虑。大多数不错的数据库都具有导出到CSV功能,可以执行此任务无疑要高效。如果是mysql,则可以使用 LOAD DATA INFILE 为此命令。

我们为此目的开发了一个Java库,目前可以作为开源项目可用 https://github.com/jbaliuka/x4j-analytic 。我们将其用于操作报告。我们生成庞大的Excel文件,约200,000个应该没有问题,Excel也设法打开此类文件。我们的代码使用POI加载模板,但生成的内容直接流到了内存中的XML或对象模型层的情况下。

当您将数据插入单元格或执行数据计算/生成时,是否会发生此内存问题?

如果要将文件加载到由预定义的静态模板格式组成的Excel中,则最好保存模板并多次重复使用。通常,当您要生成每日销售报告或等...

否则,每次您需要从头开始创建新的行,边框,列等。

到目前为止,Apache Poi是我发现的唯一选择。

“很明显,写〜20k行(每行中有10-20列)给了我可怕的“ java.lang.outofmemoryerror:java heap space”。

“企业”

您可以做的是 - 执行批处理数据插入。创建一个queuetask表,每次生成1页之后,休息几秒钟,然后继续第二部分。如果您担心队列任务期间的动态数据更改,则可以首先将主键输入Excel(通过隐藏并锁定从用户视图中的列)。第一次运行将是插入主键,然后第二个队列从记事本读出,并按部分完成任务。

我们做了一些相似的数据,因此我们不得不改用Jexcelapi,因为POI的资源很重。尝试Jexcelapi,当您必须操纵大型Excel-Files时,您将不会后悔!

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top