解决SXSSF使用时“Attempting to write a
2018-09-22 本文已影响169人
小浊微清
在开发中,使用SXSSFWorkbook构建导出excel时,可能会遇到“Attempting to write a row[?] in the range [0,?]that is already written to disk.”的报错情况,如下图所示。
bug对于这种情况下,需要我们详细分析,首先时这个错误时从哪儿抛出的,通过源码分析,查看到在SXSSFSheet的createRow函数中找到这样一个抛出异常的位置。
...
if (rownum <= this._writer.getLastFlushedRow()) {
throw new IllegalArgumentException("Attempting to write a row[" + rownum + "] " + "in the range [0," + this._writer.getLastFlushedRow() + "] that is already written to disk.");
} else if (this._sh.getPhysicalNumberOfRows() > 0 && rownum <= this._sh.getLastRowNum()) {
throw new IllegalArgumentException("Attempting to write a row[" + rownum + "] " + "in the range [0," + this._sh.getLastRowNum() + "] that is already written to disk.");
} else {
...
分析这段异常的原因,当前要创建的行小于等于最近已经创建的行时,就会抛出异常。因此这个要求是,我们不能在已经创建行的位置再创建行。
究其原因,是在于SXSSFWorkbook的本身实现方式,其本身实现方式在于,不断的将一定行数的表格写入临时文件,最终将所有的临时文件合并起来,这种方式中保证了内存的占用数理想,并且导出的效率也比较理想。
在这种实现中,如果一个行已经写入临时文件了,就不能再修改了,因此在源代码中直接限制了重复创建并写同一栏,并在此抛出异常。
解决方案
1、使用HSSFWorkbook、XSSFWorkbook替代SXSSFWorkbook。这种方式中要么是在HSSFWorkbook中仅支持xls,并且导出的数量有限,并且导出文件效率也较低,内存占用较大;虽然在XSSFWorkbook中,导出效率提高了,使用了xlsx格式,导出数量限制也大大放宽,但是内存占用问题依然没有得到解决。
2、避免在已经创建的行上重新创建行,使用getRow代替重复创建的情况。
注:多数情况下,这种情况的出现,都是因为程序行数计数标志出现了重复、计数错误等情况导致的。