linenumberreader 是 bufferedreader 的子类,天然支持缓冲读取和行号追踪,调用 setlinenumber() 设置起始行号,readline() 后用 getlinenumber() - 1 获取当前行号,比手动计数更健壮、语义清晰。

Java 中 BufferedReader 本身不提供行号功能,但可以和 LineNumberReader 配合使用——因为 LineNumberReader 是 BufferedReader 的子类,天然支持缓冲读取 + 行号追踪。
用 LineNumberReader 替代 BufferedReader 获取行号
LineNumberReader 继承自 BufferedReader,所以它具备缓冲效率,同时内置行号计数器(从 0 或 1 开始可调)。直接用它替换原来的 BufferedReader 即可,无需额外包装。
- 创建时传入
Reader(如FileReader或InputStreamReader) - 默认行号从 0 开始,调用
setLineNumber(int)可设为从 1 开始(更符合习惯) - 每调用一次
readLine(),内部行号自动 +1 - 通过
getLineNumber()获取当前已读行的行号(注意:是下一行的编号,即刚读完第 n 行后返回 n+1,除非提前调整)
读取时带行号输出的典型写法
下面是一个安全、清晰的示例(含异常处理和资源关闭):
try (LineNumberReader reader = new LineNumberReader(new FileReader("data.txt"))) {
reader.setLineNumber(1); // 从 1 开始计数
String line;
while ((line = reader.readLine()) != null) {
int lineNumber = reader.getLineNumber(); // 注意:此时已读完该行,行号已是下一行号
System.out.println(lineNumber + ": " + line);
}
} catch (IOException e) {
e.printStackTrace();
}
⚠️ 注意:getLineNumber() 返回的是「下一个将被读取的行」的编号。所以如果想让输出的行号与当前读到的行一致,应在 readLine() 后立刻获取,并理解其语义——上面代码中设置起始为 1,readLine() 读第一行后 getLineNumber() 返回 2?不对!实际行为是:调用 setLineNumber(1) 后,第一次 readLine() 返回第 1 行,紧接着调用 getLineNumber() 返回 2 —— 所以更稳妥的做法是用 reader.getLineNumber() - 1 表示当前行号,或在读之前先加 1:
- 推荐写法:读完后用
reader.getLineNumber() - 1得到当前行号 - 或初始化后立即
reader.setLineNumber(0),之后每次读完就用getLineNumber()(此时返回的就是刚读的行号)
结合正则或内容做带行号的替换
如果需求是「找出某行并替换内容,同时保留/标记行号」,可边读边判断,构建新内容:
- 用
LineNumberReader逐行读,记录getLineNumber() - 1作为当前行号 - 对每行做匹配(如
line.contains("old")或line.replaceAll(...)) - 将处理后的行(含行号前缀或原样)写入新文件或收集到
List<string></string> - 避免直接修改原文件,推荐“读-处理-写新文件-替换”流程
例如:把包含 "TODO" 的行替换成 "[DONE] ..." 并加上行号前缀:
List<string> result = new ArrayList();
try (LineNumberReader reader = new LineNumberReader(new FileReader("src.txt"))) {
reader.setLineNumber(0);
String line;
while ((line = reader.readLine()) != null) {
int currentLine = reader.getLineNumber();
if (line.contains("TODO")) {
line = String.format("%d: [DONE] %s", currentLine, line.replace("TODO", ""));
} else {
line = currentLine + ": " + line;
}
result.add(line);
}
}</string>
为什么不直接用 BufferedReader + 手动计数?
手动维护行号(如 int lineNo = 0;,每次循环 lineNo++)也能实现,但 LineNumberReader 的优势在于:
- 自动处理
mark()/reset()时的行号同步(手动计数容易出错) - 在跳过、回退、异常中断等边界场景下更健壮
- 语义明确,代码可读性高
除非有特殊兼容要求,否则优先选用 LineNumberReader 替代裸 BufferedReader 来获得行号能力。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











