我需要在已经存在的模板(.xlsx)上的Excel(.xlsx)文件中写入数百万条记录。最初,我使用的是XSSFWorkbook,这显然导致我遇到OOM问题。

然后,为了避免出现如下OOM问题,我更改为SXSSFWorkbook,

FileInputStream fis = new FileInputStream(file);
OPCPackage pkg = OPCPackage.open(fis);
XSSFWorkbook mainBook = new XSSFWorkbook(pkg);
SXSSFWorkbook wb = new SXSSFWorkbook(mainBook,200);
Sheet sh = wb.getSheet("Sheet1");
Row row0 = sh.createRow(0);


在SXSSFWorkbook中,我们无法修改现有模板,因此我将模板保留为空以写入具有列标题的数据。

但是在row0 = sh.createRow(0);上,它会抛出类似“ java.lang.IllegalArgumentException:尝试在已写入磁盘的row[0]范围内写入[0,106403]”的错误。

我不确定,如何将“ 106403”写入磁盘,该怎么办?

因此对这三个产生了疑问,


什么是FlushedRows,如何在尝试创建新行时刷新行106403?
什么是“写入磁盘”?
在使用参数“ rowAccessWindowSize”初始化“ SXSSFWorkbook”时,在我的情况下为200,rowAccessWindowSize是什么,它将做什么?

最佳答案

SXSSFWorkbook仅用于写入。使用模板XSSFWorkbook时,从该SXSSFWorkbook创建XSSFWorkbook时,将为该XSSFWorkbook中的每个工作表创建一个临时文件,并将这些工作表中的所有现有行写入这些临时文件中。以后,只有新行可以流式传输到这些临时文件中。

rowAccessWindowSize设置在刷新到临时文件之前保留在内存中的行数。已经写入临时工作表文件的所有行以后将无法再访问,因为它们不在内存中,而仅在临时文件中。这就是SXSSF内存使用率低的原因。

错误消息java.lang.IllegalArgumentException: Attempting to write a row[0] in the range [0,106403] that is already written to disk.告诉您索引0到106403(行1到106404)的行已被写入磁盘。这表明模板Sheet1不为空。至少在行106404中必须是数据。这就是为什么在Sheet1时将行1至106404写入SXSSFWorkbook wb = new SXSSFWorkbook(mainBook,200);的临时文件的原因。之后,只能在SXSSFSheet上创建大于行号106405的行。

07-25 23:22