Apache POI:检查列是否为空

时间:2016-07-05 13:36:26

标签: java excel apache-poi

我需要检查.xlsx文件中的列是否为空,但找不到比这更平滑的内容:

    public static boolean isColumnEmpty(int column, int firstRow, XSSFSheet sheet) {


    XSSFRow row = sheet.getRow(firstRow);

    while (row != null) {
        Cell c = row.getCell(column, Row.RETURN_BLANK_AS_NULL);
        if (c != null) {
            return false;
        }
        row = sheet.getRow(firstRow++);
    }
    return true;

}

firstRow只是您想要开始的行(实际上我的列不是完全空的,还有一个标题)。

我想知道你们中有些人是否有更好的想法!

1 个答案:

答案 0 :(得分:2)

答案取决于工作表中物理行的稀疏程度,编写简单代码的愿望,以及您对执行速度的关注程度。

三者的良好折衷只会循环通过物理行,只要startRowgetFirstRowNum()更接近getLastRowNum(),就可以很好地执行。

public static boolean isColumnEmpty(Sheet sheet, int columnIndex, int startRow) {
    for (Row row : sheet) {
        if (row.getRowNum() < startRow) continue;
        Cell cell = row.getCell(columnIndex, Row.RETURN_BLANK_AS_NULL);
        if (cell != null) {
            return false;
        }
    }
    return true;
}

对于密集行的工作簿,您的代码更好。

对于工作量最少的代码,您可以将这两种方法结合起来(我更喜欢for - 循环遍历while - 循环,因为它可以更快地验证您的代码获胜&# 39;陷入无限循环中)

public static boolean isColumnEmpty(Sheet sheet, int columnIndex, int startRow) {
    int firstRow = sheet.getFirstRowNum();
    int lastRow = sheet.getLastRowNum();
    // No need to check rows above the first row
    startRow = Math.max(startRow, firstRow);
    int numRows = sheet.getPhysicalNumberOfRows();

    // Compute an estimate of the number of rows that each method
    // will access.
    // Assume the cost to access one row is the same
    // between an explicit getRow() or through the rowIterator.
    // Assume physical rows are uniformly spaced, which is unlikely true
    // but the best estimate possible without iterating over the rows.
    double rowDensity = (lastRow - firstRow + 1) / numRows;
    double estimatedForEachLoopCost = numRows;
    double estimatedForLoopCost = (lastRow - startRow) + 1) * rowDensity;
    if (estimatedForEachLoopCost < estimatedForLoopCost) {
        // for-each iteration
        for (Row row : sheet) {
            if (row.getRowNum() < startRow) continue;
            Cell cell = row.getCell(columnIndex, Row.RETURN_BLANK_AS_NULL);
            if (cell != null) {
                return false;
            }
        }
        return true;
    } else {
        for (int r=startRow; r<=lastRow; r++) {
            Row row = sheet.getRow(r);
            if (row == null) continue;
            Cell cell = row.getCell(columnIndex, Row.RETURN_BLANK_AS_NULL);
            if (cell != null) {
                return false;
            }
        }
        return true;
    }
}

如果真的关心性能,您可以派生POI并编写一个方法来公开TreeMap<Integer, XSSFRow>用于访问行的XSSFSheet。 然后,您可以使用_rows.tailMap(startRow, inclusive=true)访问最少的行数。

如果您在POI bugzilla上添加了一个补丁和测试用例,以获取从HSSF,XSSF和SXSSF返回java.util.Collections.unmodifiableSortedMap(_rows.subMap(startRow, true, endRow, true))的方法(如果起始行或结束行在访问窗口之外,则会失败,或者使用列跟踪器类似于autosize column tracker),然后将isColumnEmpty函数添加到相应的类中,如果您的补丁被接受,则可以避免维护fork。