如何使用Apache POI的SXSSFWorkbook更新指定单元格且不修改同行其他数据
问题原因与解决方法
两个错误版本的问题说明
- 第一版错误:
你创建SXSSFWorkbook后,仍然操作原始XSSFWorkbook的Sheet对象wb.getSheetAt(0),调用createRow(0)会直接覆盖原有第0行的所有数据,所以同一行其他单元格内容全部丢失。 - 第二版错误:
SXSSFWorkbook是流式处理类,默认会将超出你设置的窗口大小(你设置的100行)的行自动刷入磁盘,已经写入磁盘的行无法再修改。你调用createRow(0)时第0行已经被刷入磁盘,因此抛出IllegalArgumentException异常。且不管行有没有被刷盘,直接调用createRow都会覆盖原有行的所有内容,也会导致其他单元格丢失。
正确实现逻辑
要修改已有Excel的指定单元格,遵循以下规则:
- 优先用
getRow()获取已有行,行不存在时再调用createRow()新建 - 优先用
getCell()获取已有单元格,单元格不存在时再调用createCell()新建 - 如果要修改的行编号小于当前SXSSF的刷盘阈值,可以提前将需要修改的行加载到内存避免被刷盘,或如果修改的行范围很小,直接用
XSSFWorkbook处理即可,不需要用SXSSF。
可运行的正确代码
加载已有文件的部分调整后:
final String FILE_NAME = "./sxssf_example.xlsx"; FileInputStream excelInputStream = new FileInputStream(new File(FILE_NAME)); XSSFWorkbook wb = new XSSFWorkbook(excelInputStream); excelInputStream.close();
修改单元格的部分:
// 如果文件行数小于1万,可直接用XSSF处理,无需引入SXSSF的流式复杂度 SXSSFWorkbook wbss = new SXSSFWorkbook(wb, 100); Sheet swbss = wbss.getSheetAt(0); // 先读取已有行,不存在时再新建 Row row0 = swbss.getRow(0); if (row0 == null) { row0 = swbss.createRow(0); } // 先读取已有单元格,不存在时再新建 Cell cell = row0.getCell(0); if (cell == null) { cell = row0.createCell(0); } cell.setCellValue("jkkjh"); // 输出文件 final String FILE_NAME2 = "./new.xlsx"; FileOutputStream outputStream = new FileOutputStream(FILE_NAME2); wbss.write(outputStream); outputStream.close(); wbss.dispose(); wbss.close(); wb.close();
补充说明
如果必须使用SXSSF处理大文件,且需要修改的行号超过你设置的窗口大小,建议将窗口参数调大到大于你需要修改的最大行号,避免目标行被提前刷入磁盘无法修改。
内容的提问来源于stack exchange,提问作者Plain_Dude_Sleeping_Alone
相关产品推荐
相关产品推荐

