使用POI读取Excel存入二维数组丢失最后一行的解决方法咨询
解决POI读取Excel缺失最后一行的问题
问题根源
Apache POI的getLastRowNum()方法返回的是最后一行的索引值(从0开始计数),而非总行数。比如表格有3行数据,行索引为0、1、2,getLastRowNum()会返回2。如果直接用这个值作为数组长度和循环上限,循环只会执行r < 2(即遍历0、1行),自然漏掉最后一行。
除了+1之外的优化方案
方案1:使用行迭代器遍历(推荐)
POI提供了行迭代器,无需手动处理行号,既能避免索引计算错误,还能灵活处理空行:
String filePath = "C:\\testXL.xlsx"; FileInputStream fis = new FileInputStream(filePath); XSSFWorkbook wb = new XSSFWorkbook(fis); XSSFSheet ws = wb.getSheet("Sheet1"); // 先确认首行存在再获取列数 XSSFRow headerRow = ws.getRow(0); if (headerRow == null) { // 处理空表格情况 fis.close(); wb.close(); return; } int cols = headerRow.getLastCellNum(); // 用List存储数据,无需提前确定总行数 List<String[]> rowList = new ArrayList<>(); // 遍历所有有效行 Iterator<Row> rowIterator = ws.iterator(); while (rowIterator.hasNext()) { XSSFRow currentRow = (XSSFRow) rowIterator.next(); String[] rowData = new String[cols]; for (int c = 0; c < cols; c++) { Cell cell = currentRow.getCell(c); // 处理空单元格,避免空指针 rowData[c] = cell != null ? cell.toString() : ""; System.out.print(rowData[c] + "\t"); } rowList.add(rowData); System.out.println(); } // 按需转为二维数组 String[][] rowCol = rowList.toArray(new String[0][]); // 记得关闭资源 fis.close(); wb.close();
这个方案的优势:
- 完全规避行索引计算错误,自动遍历所有有效行
- 用List动态存储,无需提前预估总行数
- 可轻松过滤或保留空行(根据业务需求调整)
方案2:调整循环边界(保留数组方式)
如果坚持用数组+索引循环,除了给getLastRowNum()加1,还可以直接修改循环条件,逻辑更清晰:
String filePath = "C:\\testXL.xlsx"; FileInputStream fis = new FileInputStream(filePath); XSSFWorkbook wb = new XSSFWorkbook(fis); XSSFSheet ws = wb.getSheet("Sheet1"); XSSFRow headerRow = ws.getRow(0); if (headerRow == null) { fis.close(); wb.close(); return; } int cols = headerRow.getLastCellNum(); int lastRowIndex = ws.getLastRowNum(); // 总行数 = 最后一行索引 + 1 String[][] rowCol = new String[lastRowIndex + 1][cols]; // 循环条件改为 r <= lastRowIndex,覆盖所有行索引 for (int r = 0; r <= lastRowIndex; r++){ XSSFRow currentRow = ws.getRow(r); // 处理空行,避免空指针 if (currentRow == null) { rowCol[r] = new String[cols]; continue; } for (int c = 0; c < cols; c++){ Cell cell = currentRow.getCell(c); rowCol[r][c] = cell != null ? cell.toString() : ""; System.out.print(rowCol[r][c] + "\t"); } System.out.println(); } fis.close(); wb.close();
这里额外优化了空行和空单元格的判断,避免运行时抛出NullPointerException。
额外优化建议
直接调用cell.toString()可能导致非字符串类型单元格的结果不符合预期(比如日期会显示为数字或乱码字符串),可以根据单元格类型做格式化处理:
private String getCellValue(Cell cell) { if (cell == null) return ""; switch (cell.getCellType()) { case STRING: return cell.getStringCellValue(); case NUMERIC: if (DateUtil.isCellDateFormatted(cell)) { return new SimpleDateFormat("yyyy-MM-dd").format(cell.getDateCellValue()); } else { return String.valueOf(cell.getNumericCellValue()); } case BOOLEAN: return String.valueOf(cell.getBooleanCellValue()); case FORMULA: return cell.getCellFormula(); default: return ""; } }
内容的提问来源于stack exchange,提问作者Ami
相关产品推荐
相关产品推荐

