如何使用Apache POI检查Excel单元格是否为空?

53

我正在使用Poi.jar从Excel表格中获取输入,想知道如何检查单元格是否为空。

目前我正在使用以下代码。

cell = myRow.getCell(3);
if (cell != null) {
    cell.setCellType(Cell.CELL_TYPE_STRING);

    //System.out.print(cell.getStringCellValue() + "\t\t");
    if (cell.getStringCellValue() != "")
        depend[p] = Integer.parseInt(cell.getStringCellValue());

    }
}

5
if(cell.getStringCellValue() != "") 错误,应该改为 if(!cell.getStringCellValue().equals("")) - Lion
12个回答

79

如果你正在使用Apache POI 4.x,你可以使用以下方法:

 Cell c = row.getCell(3);
 if (c == null || c.getCellType() == CellType.Blank) {
    // This cell is empty
 }

对于旧版Apache POI 3.x,在移动到 CellType 枚举之前,它是:

 Cell c = row.getCell(3);
 if (c == null || c.getCellType() == Cell.CELL_TYPE_BLANK) {
    // This cell is empty
 }

不要忘记检查 Row 是否为 null - 如果该行从未使用过,没有单元格被使用或者样式化,该行本身可能为 null!


1
在某些情况下,这会给我带来 NPE。 - tanvi
3
请确保该行不为空——对于非空行,这段代码已包含单元格的空值检查,因此可以正常工作! - Gagravarr
3
如果 row == null,那么怎么办呢?可以针对空行进行一些操作。 - Gagravarr
1
@winklerrr Excel应该将空字符串写成空单元格,这样就不会发生这种情况。 - Gagravarr
1
@irJvV 你只需要等待Apache POI 4.0版本,那时就不会出现这种情况了,因为它已经从int转换为enum! - Gagravarr
显示剩余7条评论

34

Gagravarr的回答非常好!


检查Excel单元格是否为空

但是,如果您假设一个单元格包含空字符串("")也为空,那么您需要一些额外的代码。这可能会发生,如果一个单元格被编辑然后没有正确清除(有关如何正确清除单元格,请参见下面的进一步操作)。

我写了一个工具来检查一个XSSFCell是否为空(包括空字符串)。

 /**
 * Checks if the value of a given {@link XSSFCell} is empty.
 * 
 * @param cell
 *            The {@link XSSFCell}.
 * @return {@code true} if the {@link XSSFCell} is empty. {@code false}
 *         otherwise.
 */
public static boolean isCellEmpty(final XSSFCell cell) {
    if (cell == null) { // use row.getCell(x, Row.CREATE_NULL_AS_BLANK) to avoid null cells
        return true;
    }

    if (cell.getCellType() == Cell.CELL_TYPE_BLANK) {
        return true;
    }

    if (cell.getCellType() == Cell.CELL_TYPE_STRING && cell.getStringCellValue().trim().isEmpty()) {
        return true;
    }

    return false;
}

注意使用更新的POI版本

自版本3.15 Beta 3起,他们首先将getCellType()更改为getCellTypeEnum(),然后在版本4.0中又改回了getCellType()

  • 版本>= 3.15 Beta 3

    • 使用CellType.BLANKCellType.STRING代替Cell.CELL_TYPE_BLANKCell.CELL_TYPE_STRING
  • 版本>= 3.15 Beta 3并且版本< 4.0

    • 使用Cell.getCellTypeEnum()而不是Cell.getCellType()

但最好还是自己仔细检查,因为他们计划在未来版本中再次更改它。


示例

以下JUnit测试显示需要额外检查空值的情况。

场景:单元格的内容在Java程序中更改。稍后,在同一Java程序中,检查该单元格是否为空。如果isCellEmpty(XSSFCell cell)函数不检查空字符串,则测试将失败。

@Test
public void testIsCellEmpty_CellHasEmptyString_ReturnTrue() {
    // Arrange
    XSSFCell cell = new XSSFWorkbook().createSheet().createRow(0).createCell(0);

    boolean expectedValue = true;
    boolean actualValue;

    // Act
    cell.setCellValue("foo");
    cell.setCellValue("bar");
    cell.setCellValue(" ");
    actualValue = isCellEmpty(cell);

    // Assert
    Assert.assertEquals(expectedValue, actualValue);
}

另外:正确清除单元格内容

以防有人想知道如何正确清除单元格的内容,有两种方法可以实现(我推荐使用方法1)。

// way 1
public static void clearCell(final XSSFCell cell) {
    cell.setCellType(Cell.CELL_TYPE_BLANK);
}

// way 2
public static void clearCell(final XSSFCell cell) {
    String nullString = null;
    cell.setCellValue(nullString); 
}

为什么选择第一种方式?显式优于隐式(感谢 Python)

方式 1:将单元格类型明确地设置回空白
方式 2:由于在将单元格值设置为null字符串时产生的副作用,将单元格类型隐式地设置回空白


有用的来源

致敬 winklerrr


1
数字方面怎么样?单元格可以是NUMERIC类型但仍为空吗? - Jan Zyka
@JanZyka 不,数字单元格至少会有一个值为0。因此,您可以在工作表中看到该值。数字单元格不能以这种方式“为空”,因为您无法将单元格的值设置为null双精度值。如您所见,双精度值的setter仅接受原始双精度类型在此处。相比之下,字符串值的setter也接受null值,这将导致单元格类型自动转换为CellType.BLANK - winklerrr
1
@Sandro感谢您对trim()方法的评论。忘记了这种情况。我已相应地编辑了我的答案。 - winklerrr
我刚刚删除了我的回答,因为似乎无法很好地格式化多行代码片段。我改为创建了一个新的回答。 - Sandro

6

从Apache POI 3.17开始,您需要使用枚举来检查单元格是否为空:

import org.apache.poi.ss.usermodel.CellType;

if(cell == null || cell.getCellTypeEnum() == CellType.BLANK) { ... }

4
Cell cell = row.getCell(x, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);

这个技巧对我很有帮助,看看它是否对你有用。

2

首先,为了避免空指针异常,您需要添加以下代码:

Row.MissingCellPolicy.CREATE_NULL_AS_BLANK

这将创建一个空单元格,而不是返回NPE,然后您可以像@Gagravarr所说的那样检查以确保没有出错。
Cell cell = row.getCell(j, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
    if (cell == null || cell.getCellTypeEnum() == CellType.BLANK) 
        // do what you want

2

这是我认为到目前为止POI 3.1.7至POI 4最安全、最简洁的方法:

boolean isBlankCell = CellType.BLANK == cell.getCellTypeEnum();
boolean isEmptyStringCell = CellType.STRING == cell.getCellTypeEnum() && cell.getStringCellValue().trim().isEmpty(); 

if (isBlankCell || isEmptyStringCell) {
    ...

从POI 4开始,getCellTypeEnum()将被弃用,改为使用getCellType(),但返回类型应保持不变。


1
请注意:在POI Apache 3.15中,已经不推荐使用该方法,但在版本4中,它被重新命名为getCellType() - winklerrr

1

Row.MissingCellPolicy.CREATE_NULL_AS_BLANK 在我的情况下有效。

total_colume = myRow.getLastCellNum();
int current_colume = 0;
HSSFCell ReadInCellValue;

while (current_colume <= total_colume) {
   ReadInCellValue = myRow.getCell(current_colume, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);//if cell is empty, return black
   if (ReadInCellValue.toString=="") Log.d("empty cell", "colume=" + String.valuOf(current_colume));
   current_colume++;
}

0

Cell.getCellType()在最新的POI API中已被弃用。 如果您正在使用POI API版本3.17,请使用以下代码:

if (Cell.getCellTypeEnum() == CellType.BLANK) {
    //do your stuff here
}

请注意:在POI Apache 3.15版本中已经弃用了该方法,但是在4.0版本中它又被称为 getCellType() - winklerrr

0
.getCellType() != Cell.CELL_TYPE_BLANK

4
请注意,只有代码作为答案是不被鼓励的! - GhostCat

0

还有另外一种选择。

row=(Row) sheet.getRow(i);
        if (row == null || isEmptyRow(row)) {
            return;
        }
Iterator<Cell> cells = row.cellIterator();
    while (cells.hasNext())
     {}

当前正在迭代的单元格是否为空,有哪个检查点? - winklerrr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接