如何不使用VBA获取Excel工作表的UsedRange(已用区域)?
获取Excel工作表已用区域(UsedRange)的Groovy/POI实现
核心问题说明
Apache POI没有提供直接返回工作表已用区域的API,需要自行计算。getLastRowNum()是可靠的(返回最后一个有数据/样式的行索引,不会因中间空行中断),之前的问题是代码逻辑错误;访问空单元格需指定MissingCellPolicy,同时要完整计算首行、首列、末行、末列的边界,才能生成如A1:B2格式的范围。
完整解决方案代码
import org.apache.poi.ss.usermodel.WorkbookFactory import org.apache.poi.ss.usermodel.Row def getUsedRange(String filePath, int sheetIndex) { def workbook = WorkbookFactory.create(new File(filePath)) def sheet = workbook.getSheetAt(sheetIndex) if (!sheet) return null // 初始化边界值:首行设为最大可能索引,首列设为最大整数,末行/列设为最小可能值 int firstRow = sheet.getLastRowNum() int firstCol = Integer.MAX_VALUE int lastRow = -1 int lastCol = -1 // 遍历所有存在的行(从第一个到最后一个行索引) for (int rowNum = sheet.getFirstRowNum(); rowNum <= sheet.getLastRowNum(); rowNum++) { Row row = sheet.getRow(rowNum) if (!row) continue // 更新首行和末行边界 if (rowNum < firstRow) firstRow = rowNum if (rowNum > lastRow) lastRow = rowNum int cellCount = row.getLastCellNum() // 遍历当前行的所有单元格(包括空单元格) for (int colNum = 0; colNum < cellCount; colNum++) { // 强制返回空单元格,避免跳过空白单元格 def cell = row.getCell(colNum, Row.MissingCellPolicy.RETURN_NULL_AND_BLANK) if (!cell) continue // 更新首列和末列边界 if (colNum < firstCol) firstCol = colNum if (colNum > lastCol) lastCol = colNum } } // 检查是否存在有效单元格 if (firstRow > lastRow || firstCol > lastCol) return null // 转换为A1格式的单元格引用范围 def startCellRef = sheet.getRow(firstRow).getCell(firstCol).getReference() def endCellRef = sheet.getRow(lastRow).getCell(lastCol).getReference() return "${startCellRef}:${endCellRef}" } // 测试调用示例 def usedRange = getUsedRange("./webapps/etlserver/data/files/test_ws.xlsx", 0) LOG.info("工作表已用区域:${usedRange}")
关键细节说明
- 边界计算逻辑:通过反向初始化边界值,确保遍历到第一个有效单元格时自动更新首行/列,遍历到最后一个时更新末行/列。
- 空单元格访问:使用
Row.MissingCellPolicy.RETURN_NULL_AND_BLANK,确保可以获取到空白单元格,避免因单元格为空而跳过边界更新。 - 行遍历范围:从
sheet.getFirstRowNum()到sheet.getLastRowNum(),覆盖所有可能存在数据的行,包括中间的空行。
关于宏表函数的补充说明
GET.WORKBOOK属于Excel宏表函数,POI对这类函数的支持有限,且命名区域无法通过这类函数直接返回已用区域(宏表函数通常依赖VBA环境),因此不推荐使用该方案。
内容的提问来源于stack exchange,提问作者bosskay972
相关产品推荐
相关产品推荐

