使用java编写巨大的excel文件的API
我正在寻找使用Java以编程方式写入Excel(.xls MS Excel 2003格式)文件。 Excel的输出文件可能包含约200,000行,我打算分割的张数(每页64k行,由于Excel的限制)。
我已经尝试使用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行到文件。
我正在寻找一种方式来stream到一个Excel文件,而不是build立在内存中的整个文件,然后将其写入磁盘,这将有望节省大量的内存使用。 任何替代的API或解决scheme将不胜感激,但我只限于使用Java。 谢谢! 🙂
所有现有的Java API都尝试在RAM中一次构build整个文档。 尝试编写一个符合新的xslx文件格式的XML文件。 为了让你开始,我build议在Excel中build立一个所需格式的小文件并保存。 然后打开它,检查结构,并更换你想要的部分。
维基百科有一个关于整体格式的好文章 。
尝试使用SXSSF工作簿,这是伟大的事情,对于巨大的XLS文件,其build立文件,根本不吃RAM,因为使用NIO
为了克服堆空间exception,我不得不把我的文件分成几个excel文件。 我认为大约5行22列是关于它的,所以我只是让我的逻辑,以便每5千行我会结束文件,开始一个新的,只是相应地计算文件。
在我写了20k +行的情况下,我会有4个以上不同的文件来表示数据。
看看茧项目中的HSSF序列化程序 。
HSSF序列化程序捕获SAX事件并创buildMicrosoft Excel使用的XLS格式的电子表格
还有JExcelApi,但是它使用更多的内存。 我认为你应该创build.csv文件,并在Excel中打开它。 它可以让你传递大量的数据,但是你不会做任何“超级魔术”。
考虑使用CSV格式。 这样你就不再受到内存的限制了 – 也许只有在为CSV预填充数据的时候,也可以高效的完成这个任务,比如使用LIMIT/OFFSET
来查询DB的行子集,然后立刻写入而不是在写任何行之前将整个数据库表内容拖入Java的内存中。 一张“表”中的行数的Excel限制将增加到大约一百万。
也就是说,如果数据实际上来自数据库,那么我会重新考虑一下,如果Java是适合的话。 大多数体面的数据库都有一个导出到CSV的function,可以毫无疑问更有效地完成这项任务。 例如MySQL,你可以使用LOAD DATA INFILE
命令。
我们为此目的开发了一个Java库,目前它可以作为开源项目https://github.com/jbaliuka/x4j-analytic 。 我们用它来进行操作报告。 我们生成巨大的Excel文件,〜20万应该没有问题,Excel也设法打开这样的文件。 我们的代码使用POI来加载模板,但生成的内容直接stream式传输到内存中没有XML或Object模型层的文件。
将数据插入单元格或进行数据计算/生成时,是否发生内存问题?
如果要将文件加载到由预定义的静态模板格式组成的Excel中,则最好保存模板并多次重复使用。 通常情况下,当您要生成日常销售报告或等等时发生模板案例…
否则,每次需要从头创build新的行,边界,列等。
到目前为止,Apache POI是我发现的唯一select。
“显然,写约20k行(每行有10-20列)给了我可怕的”java.lang.OutOfMemoryError:Java堆空间“。
“企业IT”
你可以做的是 – 执行批量数据插入。 创build一个queuetask表,每次生成1页后,rest几秒钟,然后继续第二部分。 如果您担心队列任务期间的dynamic数据更改,可以先将主键放入Excel中(通过隐藏和locking用户视图中的列)。 第一次运行将插入主键,然后第二个队列将从记事本中读出,并逐个执行任务。
我们做了一些非常相似的,相同数量的数据,并且我们不得不切换到JExcelapi,因为POI资源太重了。 尝试JexcelApi,当你必须操纵大的Excel文件时,你不会后悔!