Apache POI:getRow()返回null但工作表含非空行的问题排查
问题分析与解决方案
问题原因
你遇到的getRow(0)、getRow(47)返回null的情况,本质是SXSSFWorkbook的流式处理机制导致的:
SXSSF是POI针对大数据量Excel的流式实现,默认会在内存中只保留最近的100行(滑动窗口机制),超出这个范围的行被写入临时磁盘文件,此时调用getRow()获取已刷出内存的行就会返回null。你的Excel有148行,第0-47行正好超出了默认窗口,所以无法直接获取。
另外注意你的代码里存在拼写错误:sheet.getFristRowNum()应该是sheet.getFirstRowNum(),这个错误会导致编译失败,需优先修正。
解决方案
方案1:调整SXSSF窗口大小(适合小数据量)
因为你的Excel只有148行,完全可以把窗口大小设置为大于148的值,让所有行都留在内存中:
// 创建SXSSFWorkbook时指定窗口大小为200,覆盖所有行 SXSSFWorkbook workbook = new SXSSFWorkbook(200);
这样sheet.getRow(sheet.getFirstRowNum())就能正常获取到首行,后续的列宽调整逻辑可以正常执行。
方案2:流式处理时提前跟踪列宽(适合大数据量)
如果后续数据量很大,不想占用过多内存,可以在写入Excel的阶段就跟踪每一列的最大内容宽度,最后统一设置列宽,避免事后读取已刷出内存的行:
// 示例:写入数据时跟踪列宽 Map<Integer, Integer> columnMaxWidth = new HashMap<>(); Row row = sheet.createRow(rowNum); Cell cell = row.createCell(colIndex); cell.setCellValue(cellValue); // 计算当前单元格内容宽度(POI列宽单位为1/256字符宽度) int width = cellValue.toString().length() * 256; columnMaxWidth.put(colIndex, Math.max(columnMaxWidth.getOrDefault(colIndex, 0), width)); // 所有数据写入完成后,统一设置列宽 for (Map.Entry<Integer, Integer> entry : columnMaxWidth.entrySet()) { int colIndex = entry.getKey(); if (sheet instanceof SXSSFSheet) { ((SXSSFSheet) sheet).trackColumnForAutoSizing(colIndex); } sheet.setColumnWidth(colIndex, entry.getValue()); }
方案3:读取时禁用行刷出(临时方案)
如果是读取已有的Excel文件,也可以在创建SXSSFWorkbook时禁用行刷出,但不建议大数据量场景使用:
SXSSFWorkbook workbook = new SXSSFWorkbook(XSSFWorkbookFactory.create(new FileInputStream("your-file.xlsx")), Integer.MAX_VALUE);
内容的提问来源于stack exchange,提问作者Radosław Poprawa
相关产品推荐
相关产品推荐

