You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Apache POI中XSSF与SXSSFWorkbook混合使用报错求助

解决Apache POI中XSSF转SXSSF后修改已刷盘行的错误问题

我明白你遇到的困境了——同一个工作表里有两个表格,需要分别用XSSF处理行移动(Locations表)和SXSSF流式写入(Devices表),但转成SXSSF后修改行时触发了IllegalArgumentException。这个错误的核心原因很明确:SXSSFWorkbook会把超过内存缓存窗口的行刷到磁盘,已刷盘的行无法再被修改。默认情况下,Apache POI 3.15的SXSSF缓存窗口大小是100行,当你把XSSFWorkbook转成SXSSF时,原有的行如果超过这个数量,前面的行就会被刷盘,后续再操作这些行就会报错。

下面给你两种针对性的解决方案,你可以根据数据量大小选择:

方案1:直接用SXSSF处理所有操作(适合Locations表数据量小的场景)

其实SXSSFSheet也支持shiftRows和copyRows操作,只要这些行还在内存缓存里。你可以直接创建SXSSFWorkbook并设置足够大的缓存窗口,确保Locations表的所有行都不会被刷盘,这样就能一次性完成行移动、样式复制和流式写入:

FileInputStream inputStream = new FileInputStream(new File(filePath));
// 创建SXSSFWorkbook时设置足够大的缓存窗口(比如1000,根据你的Locations表行数调整)
SXSSFWorkbook sxssfWorkbook = new SXSSFWorkbook(new XSSFWorkbook(inputStream), 1000);
SXSSFSheet sxssfSheet = sxssfWorkbook.getSheet("Sheet1");

// 1. 处理Locations表的行移动
sxssfSheet.shiftRows(tab1HeaderRowNum + 1, sxssfSheet.getLastRowNum(), locationRecordsSize - 1);

// 2. 复制行样式
for(int i = 1; i < locationRecordsSize; i++){
    sxssfSheet.copyRows(tab1HeaderRowNum, tab1HeaderRowNum, tab1HeaderRowNum + i, cellCopyPolicy);
}

// 3. 流式处理Devices表(数据量大时自动刷盘,不影响前面的Locations行)
int devicesStartRow = /* 计算Devices表的起始行位置 */;
for (Device device : yourDevicesList) {
    Row row = sxssfSheet.createRow(devicesStartRow++);
    // 填充设备数据到单元格
    row.createCell(0).setCellValue(device.getId());
    row.createCell(1).setCellValue(device.getName());
    // ...其他字段
}

// 最后清理SXSSF的临时文件
sxssfWorkbook.dispose();
inputStream.close();

方案2:先读取模板内容到内存,再新建SXSSF写入(适合大数据量场景)

如果Locations表和Devices表的数据量都很大,直接用SXSSF缓存可能会导致内存溢出。这种情况下,你可以先把模板中Locations表的内容读取到内存,再新建SXSSFWorkbook从头写入,完全避免修改已刷盘行的问题:

FileInputStream inputStream = new FileInputStream(new File(filePath));
XSSFWorkbook templateWorkbook = new XSSFWorkbook(inputStream);
XSSFSheet templateSheet = templateWorkbook.getSheet("Sheet1");

// 1. 把Locations表的表头和原有数据读取到内存
List<Row> locationTemplateRows = new ArrayList<>();
int tab1LastRowNum = /* Locations表的最后一行索引 */;
for (int i = 0; i <= tab1LastRowNum; i++) {
    locationTemplateRows.add(templateSheet.getRow(i));
}

// 2. 创建新的SXSSFWorkbook
SXSSFWorkbook sxssfWorkbook = new SXSSFWorkbook();
SXSSFSheet sxssfSheet = sxssfWorkbook.createSheet("Sheet1");

// 3. 写入Locations表头和扩展的空行(带样式)
Row headerRow = sxssfSheet.createRow(tab1HeaderRowNum);
// 复制表头的样式和内容
XSSFRow originalHeader = (XSSFRow) locationTemplateRows.get(tab1HeaderRowNum);
for (Cell cell : originalHeader) {
    Cell newCell = headerRow.createCell(cell.getColumnIndex());
    newCell.setCellStyle(cell.getCellStyle());
    newCell.setCellValue(cell.getStringCellValue());
}
// 写入locationRecordsSize行带样式的空行
for(int i = 1; i < locationRecordsSize; i++){
    Row newRow = sxssfSheet.createRow(tab1HeaderRowNum + i);
    for (Cell cell : headerRow) {
        Cell newCell = newRow.createCell(cell.getColumnIndex());
        newCell.setCellStyle(cell.getCellStyle());
    }
}

// 4. 写入原来的Locations数据到移动后的位置
int dataStartRow = tab1HeaderRowNum + locationRecordsSize;
for (int i = tab1HeaderRowNum + 1; i <= tab1LastRowNum; i++) {
    XSSFRow originalRow = (XSSFRow) locationTemplateRows.get(i);
    Row newRow = sxssfSheet.createRow(dataStartRow++);
    for (Cell cell : originalRow) {
        Cell newCell = newRow.createCell(cell.getColumnIndex());
        newCell.setCellStyle(cell.getCellStyle());
        // 根据单元格类型复制值
        switch (cell.getCellType()) {
            case STRING:
                newCell.setCellValue(cell.getStringCellValue());
                break;
            case NUMERIC:
                newCell.setCellValue(cell.getNumericCellValue());
                break;
            // 按需处理其他类型(布尔、公式等)
        }
    }
}

// 5. 流式写入Devices表
int devicesStartRow = /* 计算Devices表的起始行 */;
for (Device device : yourDevicesList) {
    Row row = sxssfSheet.createRow(devicesStartRow++);
    // 填充设备数据
}

// 关闭资源
templateWorkbook.close();
inputStream.close();
sxssfWorkbook.dispose();

这两种方案都能解决你遇到的错误,方案1更简洁,方案2更适合大数据量场景,你可以根据自己的实际情况选择。

内容的提问来源于stack exchange,提问作者KDS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:21:51