如何在内存中生成Excel文件并将其流式输出?

问题描述 投票:0回答:1

我还没有找到执行以下操作的方法:

  1. 读取非常大的数据集
  2. 将数据写入 Excel 文件(避免 JVM 内存不足,但最好不要将整个数据写入磁盘)
  3. 分部分上传(在我的例子中上传到S3)

希望一点一点地完成所有这些(阅读一些,生成一些,写一些,重复)。 但还没有弄清楚我是否可以既避免内存问题又避免写入磁盘。像这样的东西也许可以工作吗? :

  1. 使用分页增量读取数据
  2. Apache POI Streaming 看起来是在内存中生成它的好方法
  3. 使用 AWS S3 分段上传增量传输

但是(2)似乎是一个问题:

Apache POI 流在内存中保留有限数量的行,这很好,但最终结果仍然是将工作簿刷新到文件。

以前有人做过类似的事情吗? (鉴于 Excel 是二进制格式压缩 XML 文件的集合,这是否可能?)

java amazon-web-services amazon-s3 apache-poi export-to-excel
1个回答
0
投票

高效地流式传输构建大型文档是一个常见问题

SXSSFWorkbook
使用滑动窗口模型提供了一个很好的框架。实际上,找到最佳方法需要在特定上下文中进行分析。

为了下面的参考,我更新了引用的example以允许调整窗口大小。此example的变体在命令行上使用,可用于评估输出。结果似乎可以在任何网络安装卷上无缝工作,但结果可能取决于该供应商产品的详细信息。实验性

DeferredSXSSFWorkbook
可能与未来相关。

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.junit.Assert;

/**
 * @see https://stackoverflow.com/q/78456843/230513
 */
public class StreamTest {

    private static final int N = 1000;
    private static final int W = 10;

    public static void main(String[] args) throws IOException {
        // keep W rows in memory, N - W rows will be flushed to disk
        var wb = new SXSSFWorkbook(W);
        var sh = wb.createSheet();
        for (int rownum = 0; rownum < N; 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);
            }
        }
        // Verify that W rows before N - W are flushed and inaccessible
        for (int rownum = N - (2 * W); rownum < N - W; rownum++) {
            Assert.assertNull(sh.getRow(rownum));
        }
        // The last W rows are still in memory
        for (int rownum = N - W; rownum < N; rownum++) {
            Assert.assertNotNull(sh.getRow(rownum));
        }
        var file = new File("sxssf.xlsx");
        try (FileOutputStream out = new FileOutputStream(file)) {
            wb.write(out);
        }
        // dispose of temporary files backing this workbook on disk
        wb.dispose();
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.