使用POI读取excel时,foreach无法读取空单元格

309 阅读2分钟

在处理Excel文件时,Apache POI的单元格遍历机制存在一个关键特性:for-each循环会跳过空单元格。以下是问题分析和解决方案:


问题分析

当使用for (Cell cell : row)时:

  1. 只会遍历已创建的真实单元格(物理存储的单元格)
  2. 空单元格会被完全跳过
  3. 导致列索引与数据位置错位

如图一可见,当前行的单元格下标是从3开始的,前面那些空单元格被视为null,则在foreach里直接就被忽略,导致读取的内容和表头无法对齐。

image.png

图一 foreach循环处理单元格

当使用for (int j=0; j<lastCellNum; j++)时:

  1. 遍历所有逻辑上的单元格索引
  2. 显式检查row.getCell(j)是否为null
  3. 能正确处理空单元格的位置占位

正确代码实现

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 = "";
        }
        // 对单元格数据的处理
    }
}

关键改进点

  1. 强制索引遍历
    通过j < lastCellNum循环确保遍历每个逻辑列位置。

  2. 安全获取单元格
    使用row.getCell(j, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK)显式处理空单元格,将其视为空白值。


补充说明

  • lastCellNum的潜在问题
    不同行的lastCellNum可能不同,可以获取全表最大列数(通过sheet.getRow(0).getLastCellNum()或其他逻辑),确保所有行按统一列数处理。本文示例中的处理的均为列数相同的数据,故不做此处理。
  • 空单元格策略
    Row.MissingCellPolicy.CREATE_NULL_AS_BLANK会将空单元格视为空白单元格,而非直接跳过,这是正确处理空值的关键。