2009-09-28 41 views
16

我正在寻找使用Java以编程方式写入excel(.xls MS Excel 2003格式)文件。 excel输出文件可能包含〜200,000行,我打算将其分割成多个页面(每页64k行,由于excel的限制)。使用java编写巨大的excel文件的API

我尝试过使用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堆空间“。

我已经尝试使用Xms和Xmx参数Xms512m和Xmx1024增加JVM初始堆和最大堆大小。仍然不能将超过150k行写入文件。

我正在寻找一种方法将流写入excel文件,而不是在将内容写入磁盘之前在内存中构建整个文件,这将有望节省大量内存使用量。任何替代API或解决方案将不胜感激,但我只限于使用Java。谢谢! :)

+0

你可以看看:http://stackoverflow.com/questions/6004379/java-write-excel-files-with-poi-event-model – ParagJ

+0

只有1024m?尝试4086(4演出)。有时我们会在工作中运行8个gms vms)。电子表格是这样设计的,甚至可以同时在电子表格的一部分上工作? –

回答

6

所有现有的Java API都尝试在RAM中一次构建整个文档。尝试编写符合新的xslx文件格式的XML文件。为了让你开始,我建议在Excel中以所需的格式构建一个小文件并保存。然后打开它并检查结构并更换你想要的零件。

维基百科有一个good article about the overall format

+0

Thanks!I没有想到xslx,但客户端使用office 2003和xslx变得有问题,他们也不能安装MS插件来将xslx转换为xls。两个词 - “企业IT”:| – Jaskirat

+0

创建文件,在Excel中打开并保存以旧格式生成报告 –

+0

报告将每天/每周生成,在excel中打开并以旧格式保存并不是真的可行 – Jaskirat

0

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

如果您打算将文件加载到由预定义的静态模板格式组成的Excel中,那么最好保存一个模板并多次重复使用。通常情况下,当您要生成日常销售报告等时发生模板案例...

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

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

“显然,写〜20k行(每行有10-20列)给了我可怕的”java.lang.OutOfMemoryError:Java堆空间“。

“企业IT”

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

+0

我们为什么要讨论任务队列? :-S 我真的不明白你想说什么。当你说使用模板时,你想让我使用jxls api还是类似的东西? – Jaskirat

2

还有JExcelApi,但它使用更多的内存。我认为你应该创建.csv文件并在Excel中打开它。它可以让你传递大量数据,但是你不会做任何“超级魔术”。

+0

分隔文件当然非常轻便!但不幸的是,这不是一个选项。没有超凡的魔法和没有数据格式等我需要写.xls文件。 :( – Jaskirat

+1

我认为你应该试着说服你的老板使用.csv,因为以后你会遇到很多缓慢工作的问题,整个webapp都无法工作,因为有10个人正在生成excel报告。 – IAdapter

0

我们做了一些非常相似,数据量相同的数据,我们不得不切换到JExcelapi,因为POI对资源来说太重了。试试JexcelApi,当你不得不操纵大的Excel文件时,你不会后悔!

+0

谢谢,我会用JExcelAPI做一个概念验证,看看它是如何针对POI的。但结构看起来很相似,所以我真的不知道它会产生多大的差异。你可以给我一些比例,如果可能的话,数字? – Jaskirat

+0

由于我们在一段时间之前就抛弃了基于POI的代码,因为与您的代码完全相同的问题,抱歉,我不能。不过,我只是看了Glassfish服务器,其他应用程序托管生成.xls文件的应用程序。它有-Xmx768m,我们从来没有导致Excel错误的Excel世代。我只生成了10 xls的45000行* 8列,堆上有574,423,040字节。希望这会有所帮助 – fvu

+0

多个xls不会是一个问题,因为一旦它们被刷新到文件,该对象可能被发送垃圾回收。所以是一个45k行×8列的excel文件将运行在768Mb以下,但是150,000 x 20列需要超过1GB,并且我不能按指数规律分配内存,这会拼写错误的设计。 :D无论如何感谢所有这一切! :) – Jaskirat

3

查看茧形项目中的HSSF serializer

The HSSF serializer catches SAX events and creates a spreadsheet in the XLS format used by Microsoft Excel

1

考虑使用CSV格式。这样你就不再受到内存的限制 - 也许只有在为CSV预填充数据的时候,也可以高效地完成这项工作,例如使用例如LIMIT/OFFSET查询DB的行子集并立即将其写入文件而不是在编写任何行之前将整个数据库表内容拖入Java的内存中。一张“表”中的行数的Excel限制将增加到大约一百万。这就是说,如果数据实际上来自数据库,那么我会高度重新考虑Java是否是适合这种情况的正确工具。大多数体面的数据库都有一个导出到CSV的功能,可以毫无疑问更有效地完成这项任务。例如,MySQL可以使用LOAD DATA INFILE命令。

4

为了克服堆空间异常,我不得不将我的文件分成几个excel文件。我认为大约5行22列是关于它的,所以我只是制作了我的逻辑,以便每隔5K行我会结束文件,开始一个新文件,并相应地对这些文件进行编码。

在我有20k +行写入的情况下,我会有4个以上不同的文件来表示数据。

+0

是的,我也有这个想法,多个Excel文件,然后可能将其压缩到一个存档。但这还不够好。无论如何谢谢你的建议。 – Jaskirat

+0

如果你想出一个解决方案,我appriciate如果你更新你的问题=)这是一个非常恼人的问题。 –

+0

现在我面临同样的问题。正在计划分割数据。但我可以知道你是如何做到这一点? –

9

尝试使用SXSSF工作簿,对巨大的XLS文件这就是伟大的事情,它的构建文件,并在所有不吃RAM,使用becase的NIO

+0

SXSSF不支持使用XLS https://stackoverflow.com/questions/20678164/saving-sxssf-as-xls-file –

1

我们开发了一个Java库,用于此目的,目前它是可用作为开源项目https://github.com/jbaliuka/x4j-analytic。我们将其用于运营报告。 我们生成巨大的Excel文件,〜200,000应该没有问题,Excel也设法打开这样的文件。 我们的代码使用POI来加载模板,但生成的内容直接流式传输到内存中没有XML或对象模型层的文件。