LineNumberReader 是 BufferedReader 子类,按行读取并跟踪行号,getLineNumber() 返回下一行号(从 0 开始),获取刚读行号需减 1;mark/reset 会同步回退行号;无设置起始行号方法,需手动偏移。

LineNumberReader 是 BufferedReader 的子类,专门用于按行读取文本并自动跟踪当前行号。它内部维护一个行计数器(从 0 开始),每次调用 readLine() 时自动递增(跳过首行前的空行或 BOM 不影响计数),可通过 getLineNumber() 获取当前已读取的**下一行的行号**(注意:不是刚读到那行的行号)。
行号从 0 开始,且 getLineNumber() 返回的是“下一行”的编号
这是最容易混淆的点:
- 构造后未读取任何内容时,getLineNumber() 返回 0;
- 第一次调用 readLine() 读取第 1 行后,行号变为 1;
- 此时再调用 getLineNumber(),返回的是 **2**(即“接下来要读的第 2 行”的编号)。
所以,若想获取**刚刚读到的那行的行号**,应在其 readLine() 调用之后、下一次读取之前,立即调用 getLineNumber() - 1。
正确获取当前行号的典型写法
- 创建
LineNumberReader实例(包装任意Reader,如FileReader或InputStreamReader) - 用循环调用
readLine()逐行读取 - 每次成功读到一行后,用
reader.getLineNumber()减 1 得到该行真实行号
示例代码:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
try (LineNumberReader reader = new LineNumberReader(new FileReader("data.txt"))) {
String line;
while ((line = reader.readLine()) != null) {
int currentLineNo = reader.getLineNumber(); // 此时返回的是下一行号
System.out.printf("第 %d 行: %s%n", currentLineNo - 1, line);
}
}
注意 reset() 和 mark()/reset() 对行号的影响
LineNumberReader 支持标记与重置,但需注意:
- 调用 mark(int) 不会重置行号;
- 调用 reset() 后,行号计数器会回退到 mark() 时的状态(包括行号值);
- 若未调用 mark() 就直接 reset(),会抛出 IOException。
因此,若逻辑中涉及回退读取位置,行号仍保持一致,无需额外同步。
立即学习“Java免费学习笔记(深入)”;
不支持设置起始行号,但可手动偏移
LineNumberReader 没有 public 方法设置初始行号(比如从第 100 行开始计数)。如果业务需要“逻辑行号 = 物理行号 + 偏移”,只能在使用时自行加减:
- 例如跳过前 5 行头信息后,把 getLineNumber() - 1 - 5 当作业务行号;
- 或封装一层工具类,在构造时传入起始偏移量,统一处理。

















