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

使用Apache POI的shiftColumns方法删除Excel列写入报错如何解决

报错成因
  • Apache POI 5.0.0本身存在版本缺陷:shiftColumns方法处理XLSX格式左移列的场景时,没有正确更新每行单元格对应的内部XML节点索引,导致后续文件写入时,程序尝试删除不存在的单元格节点,触发IndexOutOfBoundsException异常。
  • 文件读写逻辑存在风险:你直接使用原文件路径创建输出流,输出流初始化阶段就会清空原文件内容,即使后续写入失败也无法恢复,所以会出现原文件变为0KB的问题。
正确实现列删除的方案

方案1:升级POI版本(最简便)

该Bug在POI 5.2.0及以上版本已经被官方修复,直接将所有POI相关依赖(包括poi、poi-ooxml、poi-ooxml-lite等)升级到最新稳定版即可,原有shiftColumns的调用逻辑不需要修改。
注意:所有POI相关依赖的版本必须保持一致,避免出现兼容问题。

方案2:兼容POI 5.0.0的修复写法

如果受项目限制无法升级POI版本,可以在调用shiftColumns之后手动清理错位的单元格,修复索引错乱问题,再执行写入操作,参考代码如下:

// 原有列左移逻辑
sheet.shiftColumns(2, 5, -1); 

// 新增:手动修复行内单元格索引
for (Row row : sheet) {
    XSSFRow xssfRow = (XSSFRow) row;
    // 移除左移后冗余的最右侧列单元格
    Cell redundantCell = xssfRow.getCell(5);
    if (redundantCell != null) {
        xssfRow.removeCell(redundantCell);
    }
    // 强制刷新行内单元格索引
    xssfRow.onDocumentWrite();
}

// 新增:先写入临时文件,确认成功后再覆盖原文件,避免原文件损坏
String tempPath = path + ".tmp";
try (OutputStream fileOut = new FileOutputStream(tempPath)) {
    wb.write(fileOut);
}
// 写入成功后替换原文件
Files.delete(Paths.get(path));
Files.move(Paths.get(tempPath), Paths.get(path));

额外注意事项

  • POI的列索引从0开始计数,操作前请确认要删除的列、要移动的列范围索引是否符合预期。
  • 如果需要删除多列,建议从右往左依次操作,避免前序删除导致的索引偏移引发删除错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 02:15:03