【发布时间】:2010-04-20 08:49:02
【问题描述】:
我在我的网络服务器上构建了一个非常大的 POI 工作簿。将整个工作簿保存在内存中,不会针对多个并发请求进行扩展。有没有办法可以逐步将工作簿写入 servlet 输出流。这应该会减少响应时间,并提高进程内存效率。
【问题讨论】:
标签: java servlets apache-poi
我在我的网络服务器上构建了一个非常大的 POI 工作簿。将整个工作簿保存在内存中,不会针对多个并发请求进行扩展。有没有办法可以逐步将工作簿写入 servlet 输出流。这应该会减少响应时间,并提高进程内存效率。
【问题讨论】:
标签: java servlets apache-poi
如果您要生成 Excel 2007 (xslx),那么您可以调整 BigGridDemo.java 的方法,如下所述:http://web.archive.org/web/20110821054135/http://www.realdevelopers.com/blog/code/excel
解决方案是让 POI 仅生成一个容器 xslx 作为模板,并将实际电子表格数据作为 XML 流式传输到 zip 输出流中。然后由您来简化 XML 生成。
【讨论】:
自从写完其余的答案后,情况有了很大改善——流现在是 Apache Poi 的一部分。
查看SXSSFWorkbook 类和documentation here。它在工作表上使用流式窗口,将窗口外的旧行刷新到临时文件中。
这是基于hlg's answer 中使用的BigGridDemo 方法,但现在是官方分发的一部分。
这是文档中的示例:
public static void main(String[] args) throws Throwable {
// keep 100 rows in memory, exceeding rows will be flushed to disk
SXSSFWorkbook wb = new SXSSFWorkbook(100);
Sheet sh = wb.createSheet();
for(int rownum = 0; rownum < 1000; rownum++){
Row row = sh.createRow(rownum);
for(int cellnum = 0; cellnum < 10; cellnum++){
Cell cell = row.createCell(cellnum);
String address = new CellReference(cell).formatAsString();
cell.setCellValue(address);
}
}
// Rows with rownum < 900 are flushed and not accessible
for(int rownum = 0; rownum < 900; rownum++){
Assert.assertNull(sh.getRow(rownum));
}
// ther last 100 rows are still in memory
for(int rownum = 900; rownum < 1000; rownum++){
Assert.assertNotNull(sh.getRow(rownum));
}
FileOutputStream out = new FileOutputStream("/temp/sxssf.xlsx");
wb.write(out);
out.close();
// dispose of temporary files backing this workbook on disk
wb.dispose();
}
【讨论】:
SXSSFWorkbook 在后台将临时数据刷新到磁盘,因此此示例不会将整个工作簿保留在内存中。
SXSSFWorkbook。有关详细信息,请参阅类文档。
不幸的是,如果没有顺序数据,这是不可能的。我建议寻找另一种格式,例如CSV 或 XML。两者都可以顺序写出。如果它来自数据库,它甚至可以更有效地完成,因为一个体面的数据库具有内置设施,可以有效地导出到这些格式。您只需要将字节从一侧流式传输到另一侧。
【讨论】:
您是否尝试过直接使用 HttpServletResponse.getOutputStream() 的 write 方法?
请看下面的例子:
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet("new sheet");
...
OutputStream out = response.getOutputStream();
wb.write(out);
out.close();
【讨论】:
如果你使用JExcel 它具有从 Servlet 读取流代码的示例代码。 http://jexcelapi.sourceforge.net/resources/faq/
这个 API 的唯一缺点是它只支持 Excel 2003(包括 Excel 2003)。
使用 POI - 您能否不创建文件并将文件的字节提供给 servlet 输出流?
【讨论】: