1. 概述
[BufferedReader](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/io/BufferedReader.html)
是 Java 中用于简化从字符输入流中读取文本内容的一个类。它通过内部缓冲机制提升读取效率,避免频繁的 I/O 操作。
在本篇文章中,我们将深入探讨 BufferedReader
的使用方式,并结合实际代码示例进行说明。
2. 何时使用 BufferedReader
在需要从文件、网络套接字或其他字符输入源读取文本时,BufferedReader
是一个非常实用的选择。
✅ 核心优势:通过缓冲机制减少底层 I/O 操作次数
它会一次性读取一块字符数据到缓冲区中,后续读取操作直接从缓冲区获取,直到缓冲区为空才再次访问底层流。
2.1. 包装其他 Reader
BufferedReader
是典型的装饰器模式实现 ✅,其构造函数需要传入一个 Reader
实例:
BufferedReader reader =
new BufferedReader(new FileReader("src/main/resources/input.txt"));
这样我们就可以给任意 Reader
添加缓冲功能。如果不需要缓冲,也可以直接使用 FileReader
:
FileReader reader =
new FileReader("src/main/resources/input.txt");
但 BufferedReader
还提供了额外的便利方法,比如按行读取文本,这使得它在很多场景下更受欢迎。
2.2. 缓冲任意输入流
BufferedReader
可以包装任意的字符输入流。比如我们可以结合 InputStreamReader
来读取标准输入:
BufferedReader reader =
new BufferedReader(new InputStreamReader(System.in));
这个用法适用于从键盘输入、Socket 输入流、文件等任何字符输入源读取数据。
2.3. BufferedReader vs Scanner
虽然 Scanner
也能完成类似任务,但两者在功能和使用场景上存在明显差异:
特性 | BufferedReader | Scanner |
---|---|---|
线程安全 | ✅ 是 | ❌ 否 |
解析能力 | ❌ 仅读取 | ✅ 支持正则匹配解析 |
缓冲大小 | ✅ 可自定义 | ❌ 固定 |
默认缓冲大小 | ✅ 更大 | ❌ 较小 |
IOException 处理 | ✅ 强制处理 | ❌ 隐藏 |
性能 | ✅ 更快(仅读取) | ❌ 略慢(需解析) |
📌 总结:
- 如果只是逐行读取文本,推荐使用
BufferedReader
- 如果需要解析 token、数字等结构化数据,
Scanner
更合适
3. 使用 BufferedReader 读取文本
下面我们将完整演示如何初始化、使用并关闭 BufferedReader
。
3.1. 初始化 BufferedReader
使用构造函数包装 FileReader
:
BufferedReader reader =
new BufferedReader(new FileReader("src/main/resources/input.txt"));
默认缓冲区大小为 8KB,如果需要自定义:
BufferedReader reader =
new BufferedReader(new FileReader("src/main/resources/input.txt"), 16384);
还可以使用 Files
工具类更简洁地创建:
BufferedReader reader =
Files.newBufferedReader(Paths.get("src/main/resources/input.txt"));
这种方式避免了手动创建 FileReader
,推荐用于文件读取场景。
3.2. 按行读取
使用 readLine()
方法逐行读取:
public String readAllLines(BufferedReader reader) throws IOException {
StringBuilder content = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
content.append(line);
content.append(System.lineSeparator());
}
return content.toString();
}
Java 8 引入了 lines()
方法,可以用 Stream API 简化写法:
public String readAllLinesWithStream(BufferedReader reader) {
return reader.lines()
.collect(Collectors.joining(System.lineSeparator()));
}
3.3. 关闭资源
使用完毕后必须调用 close()
释放资源,推荐使用 try-with-resources:
try (BufferedReader reader =
new BufferedReader(new FileReader("src/main/resources/input.txt"))) {
return readAllLines(reader);
}
4. 其他实用方法
除了按行读取,BufferedReader
还提供了多个实用方法。
4.1. 读取单个字符
使用 read()
方法可逐字符读取:
public String readAllCharsOneByOne(BufferedReader reader) throws IOException {
StringBuilder content = new StringBuilder();
int value;
while ((value = reader.read()) != -1) {
content.append((char) value);
}
return content.toString();
}
该方法返回字符的 ASCII 值,当返回 -1 时表示已到流末尾。
4.2. 批量读取字符
使用 read(char[], int, int)
方法批量读取字符:
public String readMultipleChars(BufferedReader reader) throws IOException {
int length = 5;
char[] chars = new char[length];
int charsRead = reader.read(chars, 0, length);
String result;
if (charsRead != -1) {
result = new String(chars, 0, charsRead);
} else {
result = "";
}
return result;
}
读取最多 5 个字符,如果读不到则返回空字符串。
4.3. 跳过字符
使用 skip(long)
方法跳过指定字符数:
@Test
public void givenBufferedReader_whensSkipChars_thenOk() throws IOException {
StringBuilder result = new StringBuilder();
try (BufferedReader reader =
new BufferedReader(new StringReader("1__2__3__4__5"))) {
int value;
while ((value = reader.read()) != -1) {
result.append((char) value);
reader.skip(2L);
}
}
assertEquals("12345", result);
}
上面的例子中,我们跳过了两个下划线 _
,只保留数字。
4.4. mark 与 reset
使用 mark(int)
和 reset()
可以标记当前位置并回退:
@Test
public void givenBufferedReader_whenSkipsWhitespacesAtBeginning_thenOk()
throws IOException {
String result;
try (BufferedReader reader =
new BufferedReader(new StringReader(" Lorem ipsum dolor sit amet."))) {
do {
reader.mark(1);
} while(Character.isWhitespace(reader.read()));
reader.reset();
result = reader.readLine();
}
assertEquals("Lorem ipsum dolor sit amet.", result);
}
📌 注意:
mark(1)
表示只保留一个字符的回退能力BufferedReader
的markSupported()
总是返回true
,所以无需额外判断
虽然 mark/reset
使用频率不高,但在需要“预读”或“回退”逻辑时非常有用。
5. 小结
本文通过多个示例演示了 BufferedReader
的常见用法,包括初始化、读取文本、关闭资源以及各种辅助方法。在需要高效读取字符流的场景中,BufferedReader
是首选工具类。
📌 关键要点回顾:
- ✅ 推荐使用 try-with-resources 自动关闭资源
- ✅ 按行读取首选
readLine()
或lines()
- ✅ 自定义缓冲区大小可提升性能(建议使用 2 的幂)
- ✅
mark/reset
在需要回退时非常实用
完整示例代码可参考:GitHub 项目地址