You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Java 1.8与Apache POI 5.1.0读取Excel时第47行被跳过问题求助

问题描述

我使用的是Java 1.8、org.apache.poi 5.1.0以及org.apache.poi.ooxml 5.1.0版本。现有一个包含54行数据的Excel文件,我按5行一个块的规则读取该文件,当读取到第47行时该行被跳过,程序直接返回了新块的第一行,但预期应该返回新块上方的首个空行。
使用调试器可以看到程序直接从第46行跳转到了第48行,但我预期应当读取第47行。在第51行添加断点(位置见Java代码中的注释),可以看到currentRow的属性'r'从第46行直接跳到了第48行。
这个问题已经严重影响开发进度,导致程序无法正常使用。

以下是精简后的最小可复现相关代码:

build.gradle文件

plugins {
    id 'java'
    id 'application'
}

group 'nl.karnhuis'

sourceCompatibility = 1.8

application {
    mainClass = 'nl.karnhuis.test.Testfile'
}

repositories {
    mavenCentral()
    maven {
        url "https://mvnrepository.com/artifact"
    }
}

dependencies {
    implementation 'org.apache.poi:poi:5.1.0'
    implementation 'org.apache.poi:poi-ooxml:5.1.0'
}

gradle.settings文件

rootProject.name = 'testfile'

Java代码

package nl.karnhuis.test;

import java.io.*;
import java.util.*;

import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;

public class Testfile {

    public void run() {
        File inputFile = new File("schema.xlsx");
        handleFile(inputFile);
    }

    private void handleFile(File inputFile) {
        try {
            // 创建.xlsx文件对应的工作簿实例
            XSSFWorkbook workbook = new XSSFWorkbook(inputFile);

            // 读取第一个sheet
            Sheet datatypeSheet = workbook.getSheetAt(0);
            Iterator<Row> iterator = datatypeSheet.iterator();
            Row currentRow = null;

            // 遍历所有行
            while (iterator.hasNext()) {

                if (checkForLastLine(currentRow)) {
                    break;
                }

                currentRow = iterator.next();
                // 前两行直接跳过
                if ((currentRow.getRowNum()) < 2) {
                    continue;
                }

                currentRow = iterator.next();
                // 业务逻辑处理

                currentRow = iterator.next();
                // 业务逻辑处理

                currentRow = iterator.next();
                // 业务逻辑处理

                // 下一行是空行,直接跳过
                currentRow = iterator.next();
                System.out.println(currentRow.getRowNum()); // 在此处添加断点
            }

        } catch (IOException | InvalidFormatException e) {
            e.printStackTrace();
        }
    }

    private boolean checkForLastLine(Row currentRow) {
        if (currentRow == null) {
            return false;
        } else {
            for (Cell currentCell : currentRow) {
                // 到达文件末尾则退出循环
                return currentCell.getColumnIndex() == 0
                        && (currentCell.getStringCellValue().trim().startsWith("primaire")
                        || currentCell.getStringCellValue().trim().startsWith("secondaire"));
            }
        }
        return false;
    }

    public static void main(String[] args) {
        Testfile mc = new Testfile();
        mc.run();
    }
}
问题原因

POI 的 Sheet.iterator() 方法默认只返回Excel文件中实际存在的、有过编辑记录的行,完全未被编辑过的空白行不会被纳入迭代序列,你的第47行就是这种完全未初始化的空行,所以直接被迭代器跳过。
另外代码逻辑存在隐患:循环内连续调用5次iterator.next()却没有每次判断iterator.hasNext(),遇到文件末尾或者空行截断时,大概率会抛出NoSuchElementException。

修复方案

不要使用默认迭代器,改为按行号手动遍历,自己判断行的有效性,修改后的handleFile方法示例如下:

private void handleFile(File inputFile) {
    try {
        XSSFWorkbook workbook = new XSSFWorkbook(inputFile);
        Sheet datatypeSheet = workbook.getSheetAt(0);
        // 获取sheet实际的最后一行行号
        int lastRowNum = datatypeSheet.getLastRowNum();
        Row currentRow = null;
        // 从第0行开始按行号遍历
        for (int rowNum = 0; rowNum <= lastRowNum; rowNum++) {
            if (checkForLastLine(currentRow)) {
                break;
            }
            // 不存在的行返回null,统一按空行处理
            currentRow = datatypeSheet.getRow(rowNum);
            if (currentRow == null || currentRow.getRowNum() < 2) {
                continue;
            }
            // 按5行一个块规则读取,每次判断行号不越界
            // 处理块内第一行
            // 业务逻辑
            rowNum++;
            if (rowNum > lastRowNum) break;
            currentRow = datatypeSheet.getRow(rowNum);
            // 处理块内第二行
            // 业务逻辑
            rowNum++;
            if (rowNum > lastRowNum) break;
            currentRow = datatypeSheet.getRow(rowNum);
            // 处理块内第三行
            // 业务逻辑
            rowNum++;
            if (rowNum > lastRowNum) break;
            currentRow = datatypeSheet.getRow(rowNum);
            // 处理块内第四行
            // 业务逻辑
            rowNum++;
            if (rowNum > lastRowNum) break;
            currentRow = datatypeSheet.getRow(rowNum);
            // 处理块内第五行(空行)
            System.out.println(currentRow != null ? currentRow.getRowNum() : rowNum); // 断点位置
        }
    } catch (IOException | InvalidFormatException e) {
        e.printStackTrace();
    }
}

内容的提问来源于stack exchange,提问作者Rob The Ranger

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 05:45:04