Java LineNumberReader 设置行号后为什么不会跳行
来源:17golang原创
时间:2026-10-29 05:23:14 366浏览 收藏
LineNumberReader.setLineNumber(2)只把行号计数器设为2,不会把读取位置移动到第三行。要取文件第3行,必须实际读过前2行,再调用一次readLine()。给日志调整显示编号与按行定位是两种不同的需求。
官方地址:https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/io/LineNumberReader.html
用读取次数建立基线
假设输入依次是alpha、beta、gamma三行,每行都以换行符结束。目标是获取gamma。先记录两个指标:调用了多少次readLine,以及实际返回什么文本。不要只看getLineNumber,因为这个值可以被应用主动改写。
下面是供读者复现的独立Java示例,未在本文环境运行;输出说明来自API语义推导,不是压测记录。
import java.io.IOException;
import java.io.LineNumberReader;
import java.io.StringReader;
public class LineNumberExample {
static String readTarget(LineNumberReader reader, int target) throws IOException {
// 本方法要求新建且未消费的reader,以文件首行为第1行。
if (target
第一个reader预期返回alpha,接着打印计数3;另一个从头读取的reader预期返回gamma。前者计数看起来已到3,内容却仍是第一行,这正是误判来源。
分清计数器与读取位置
把LineNumberReader看成同时维护两类信息的包装器:读取状态决定下次能取得什么字符,行号计数用于报告当前编号。setLineNumber只关联后者;getLineNumber也不会读取数据。实际读取由readLine等读取方法完成。
在上述例子中,setLineNumber(2)使后续编号以2为基准累计。第一次readLine消费alpha及其终止符,计数成为3;它并没有因为计数基准改变而跨过alpha或beta。这个功能适合为已截取的文本片段补充编号基准,但不能代替文件定位。

顺序读取到目标行
示例的readTarget采用明确的起点约定:调用方传入刚创建、尚未消费的reader,target从1开始。循环消费target减1行,最后再取一行。目标为1时循环不执行;文件不足目标行数时返回null。空白行返回空字符串,仍是一行,不能当作文件结束。
这个辅助方法用独立局部变量row计算物理文本行,因此不会拿可被重设的getLineNumber作为停止条件。若reader已经读取过部分内容,应重新打开文件,或另行设计“相对于当前位置”的接口;不要把已消费的reader交给这个承诺从首行定位的方法。
真实文件可用Files.newBufferedReader并明确字符集,再包一层LineNumberReader,仍采用try-with-resources关闭最外层。不要在包装器读取期间绕过它去消费底层Reader;缓冲和计数状态会失去一致的解释基础。
用内容与操作数对照方案
| 方案 | 到目标3的readLine调用 | 返回内容 | 含义 |
|---|---|---|---|
| 先设计数2,再读一次 | 1次 | alpha | 修改编号,未定位 |
| 从头跳过2行,再读一次 | 3次 | gamma | 消费前缀,取得目标 |
这张表是固定输入下的操作数量推导,不是耗时或吞吐量测试。顺序读取目标N需要消费前N行对应的字符,成本取决于前缀总字符数,不能把“设置一次计数”宣传成常数时间行定位。
如果要自行比较耗时,应固定文件内容、字符集、目标行、JDK和存储条件,并区分冷热缓存、预热和重复次数,同时核对返回文本是否正确。只比较行号值或两段不同语义代码的耗时,没有业务意义。反复随机读取超大文件时,可以考虑另行构建索引,但字节偏移、字符编码和换行规则需要一起设计;本例不提供随机访问索引实现。

处理换行、回读和资源边界
LineNumberReader识别LF、CR和CRLF,CRLF作为一个行终止符。readLine返回的字符串不包含行终止符。末尾没有终止符但仍有文本时,该文本仍可构成最后一行;空文件则直接返回null。不要用字符串长度反推行数,也不要以为每行固定占用相同字节。
若只想临时读取后回到已知位置,可在标记有效范围内配合mark与reset;reset也会恢复相应行号。标记可能因超出readAheadLimit而失效,此限制按字符考虑,并不是任意行号书签。它与setLineNumber的用途不同。
skip能不能直接跳过指定行数?
skip的参数表达字符数量,不是行数。行长度和换行形式不同,不能直接把行号作为参数。
为什么刚创建时行号是0?
默认计数从0开始,是读取进展的计数基准。若业务把下一条未读记录称为第1行,应明确这个展示规则,不要为了显示编号提前改动读取位置的假设。
只要读取指定行,必须用LineNumberReader吗?
不必须。BufferedReader也可以逐行消费并用局部变量计数。只有需要读取过程中维护或调整行号时,LineNumberReader才提供额外便利。
判断改动是否正确,先核对返回内容,再解释行号。应用要跳到某行,就实际消费文本;应用只要调整编号基准,才调用setLineNumber。
-
501 收藏
-
文章 · java教程 | 1个月前 | Java · 异常处理 · 资源管理 · java try-with-resources AutoCloseable close suppressed exception501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
401 收藏
-
266 收藏
-
103 收藏
-
443 收藏
-
文章 · java教程 | 1小时前 | 网络编程 · Java · HTTP · Stream · java httpclient Stream BodyHandlers.ofLines HTTPResponse151 收藏
-
206 收藏
-
259 收藏
-
112 收藏
-
119 收藏
-
110 收藏
-
177 收藏
-
191 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习