我还没有找到执行以下操作的方法:
希望一点一点地完成所有这些(阅读一些,生成一些,写一些,重复)。 但还没有弄清楚我是否可以既避免内存问题又避免写入磁盘。像这样的东西也许可以工作吗? :
但是(2)似乎是一个问题:
Apache POI 流在内存中保留有限数量的行,这很好,但最终结果仍然是将工作簿刷新到文件。
以前有人做过类似的事情吗? (鉴于 Excel 是二进制格式压缩 XML 文件的集合,这是否可能?)
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();
}
}