在处理Excel文件时,Apache POI的单元格遍历机制存在一个关键特性:for-each循环会跳过空单元格。以下是问题分析和解决方案:
问题分析
当使用for (Cell cell : row)时:
- 只会遍历已创建的真实单元格(物理存储的单元格)
- 空单元格会被完全跳过
- 导致列索引与数据位置错位
如图一可见,当前行的单元格下标是从3开始的,前面那些空单元格被视为null,则在foreach里直接就被忽略,导致读取的内容和表头无法对齐。
图一 foreach循环处理单元格
当使用for (int j=0; j<lastCellNum; j++)时:
- 遍历所有逻辑上的单元格索引
- 显式检查
row.getCell(j)是否为null - 能正确处理空单元格的位置占位
正确代码实现
for (Row row : sheet) {
short lastCellNum = row.getLastCellNum();
// 必须使用索引循环遍历所有逻辑列
for (int j = 0; j < lastCellNum; j++) {
Cell cell = row.getCell(j, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
String cellValue;
// 按单元格类型解析值
switch (cell.getCellType()) {
case STRING:
cellValue = cell.getStringCellValue();
break;
case NUMERIC:
cellValue = String.valueOf(cell.getNumericCellValue());
break;
case BOOLEAN:
cellValue = String.valueOf(cell.getBooleanCellValue());
break;
default:
cellValue = "";
}
// 对单元格数据的处理
}
}
关键改进点
-
强制索引遍历
通过j < lastCellNum循环确保遍历每个逻辑列位置。 -
安全获取单元格
使用row.getCell(j, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK)显式处理空单元格,将其视为空白值。
补充说明
lastCellNum的潜在问题
不同行的lastCellNum可能不同,可以获取全表最大列数(通过sheet.getRow(0).getLastCellNum()或其他逻辑),确保所有行按统一列数处理。本文示例中的处理的均为列数相同的数据,故不做此处理。- 空单元格策略
Row.MissingCellPolicy.CREATE_NULL_AS_BLANK会将空单元格视为空白单元格,而非直接跳过,这是正确处理空值的关键。