linenumberreader 行号仅在 readline() 成功返回非 null 时递增,空行计数、异常不递增;手动用 setlinenumber()/getlinenumber() 控制;分词建议弃用它,改用 bufferedreader 配合自维护行号。

LineNumberReader 的行号计数逻辑非常直接:它只在调用 readLine() 时自动递增行号,且仅对成功读取到的非 null 行生效;其他读取方式(如 read()、read(char[]))完全不触发行号更新。
行号递增的唯一触发点是 readLine()
每次成功执行 readLine() 并返回非 null 字符串时,内部计数器加 1。遇到文件末尾(返回 null)或异常时,行号不再增加。这意味着:
- 空行(即内容为空字符串
"")也会被计为一行,行号照常 +1 - 如果某次
readLine()抛出异常(如IOException),行号停留在上一行,不会跳变 - 多次调用
readLine()但始终返回null(例如反复 EOF),行号不再变化
手动控制行号需调用 setLineNumber() 和 getLineNumber()
若解析过程中需要重置或修正行号(比如跳过注释块、处理嵌入式脚本),可主动调用:
-
setLineNumber(int):直接设置当前行号(不影响已读内容) -
getLineNumber():获取当前已计入的行号(从 0 开始计,首次readLine()后为 1)
注意:该类默认从 0 开始计数,首行对应行号 1 —— 这是由 readLine() 内部实现决定的,并非初始化为 1。
分词场景中行号容易失准的常见原因
在海量文本分词(如 Java 源码解析、日志结构化)中,若混合使用多种读取方式,极易导致行号与实际不符:
- 用
read()单字节读取跳过 BOM 或前导空格,行号不变,但光标已移动 - 用
skip(long)跳过大段注释,行号不更新,后续readLine()仍按原序号累加 - 缓冲区未刷写或流被包装(如套了
BufferedReader),可能造成行边界识别错位
建议:分词阶段统一用 readLine() 拆行,再对每行做 token 切分;如需逐字符处理,应自行维护行号状态,避免依赖 LineNumberReader 的自动计数。
替代方案更可控:自维护行号 + BufferedReader
对性能和准确性要求高的分词系统,通常弃用 LineNumberReader,改用:
-
BufferedReader配合手动行号计数器(初始化为 0,每次readLine()后 ++) - 遇到换行符
\n、\r\n、\r时,在流式解析中实时检测并递增 - 结合
PushbackReader回退字符,确保换行符不被吞掉,行号与原始位置严格对齐
这样既能精准匹配源码行号,又避免了 LineNumberReader 的封装黑盒和不可定制性。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











