理解 Reader 类在 Java I/O 体系中的定位与作用
掌握 Reader 的核心方法及其使用场景
能够通过子类(如 FileReader)读取文本文件
了解 mark() / reset() 等高级功能的使用条件
学会安全地管理字符流资源
Reader 是 Java 中用于读取字符流的抽象基类,位于 java.io 包中。它专为处理 16 位 Unicode 字符而设计,适用于所有文本数据的读取操作。与字节流(InputStream)不同,Reader 及其子类能自动处理字符编码(如 UTF-8、GBK),避免乱码问题,是处理文本文件的首选。

类声明
public abstract class Reader implements Readable, Closeable实现 Readable 接口:支持向 CharBuffer 写入数据
实现 Closeable 接口:提供 close() 方法释放系统资源
实际开发中,通常不会直接实例化
Reader,而是使用其具体子类。
逐字符读取文件
以下程序演示如何使用 FileReader(Reader 的子类)读取文本文件:
import java.io.*;
public class FileReaderExample {
public static void main(String[] args) {
// 确保当前目录下存在 example1.txt,内容如:
// Hello welcome to Developer Community
try (Reader reader = new FileReader("example1.txt")) {
int data;
while ((data = reader.read()) != -1) {
System.out.print((char) data);
}
} catch (IOException e) {
System.err.println("读取文件时发生错误: " + e.getMessage());
}
}
}输出:
Hello welcome to Developer Community使用 try-with-resources 语法自动关闭
Reader,无需手动调用close()
mark、skip 与缓冲读取
以下程序展示 Reader 的多种方法协同工作:
import java.io.*;
import java.nio.CharBuffer;
import java.util.Arrays;
public class ReaderAdvancedExample {
public static void main(String[] args) throws IOException {
// 假设 file.txt 内容为:"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
try (Reader reader = new FileReader("file.txt")) {
char[] buffer = new char[10];
CharBuffer charBuffer = CharBuffer.wrap(buffer);
// 检查是否支持 mark/reset
if (reader.markSupported()) {
reader.mark(100); // 标记当前位置,最多回退 100 个字符
System.out.println("mark 功能受支持");
}
// 跳过前 5 个字符(A~E)
reader.skip(5);
// 读取接下来的 10 个字符(F~O)
reader.read(buffer, 0, 10);
System.out.println("读取的字符数组: " + Arrays.toString(buffer));
// 继续读取到 CharBuffer(P~T)
reader.read(charBuffer);
System.out.println("CharBuffer 内容: " + Arrays.toString(charBuffer.array()));
// 读取下一个字符(U)
System.out.println("下一个字符: " + (char) reader.read());
}
}
}假设 file.txt 内容为:
ABCDEFGHIJKLMNOPQRSTUVWXYZ可能输出:
mark 功能受支持
读取的字符数组: [F, G, H, I, J, K, L, M, N, O]
CharBuffer 内容: [P, Q, R, S, T, K, L, M, N, O]
下一个字符: U注意:
FileReader不支持mark()/reset()!上述示例中markSupported()实际返回false。若需此功能,应使用BufferedReader。
只有部分 Reader 子类(如 BufferedReader、StringReader)支持标记功能:
import java.io.*;
public class MarkResetExample {
public static void main(String[] args) throws IOException {
String text = "Java I/O is powerful!";
try (Reader reader = new BufferedReader(new StringReader(text))) {
if (reader.markSupported()) {
reader.mark(20); // 标记位置
// 读取前 4 个字符
for (int i = 0; i < 4; i++) {
System.out.print((char) reader.read());
}
System.out.println(); // 输出 "Java"
// 回退到标记位置
reader.reset();
// 再次读取,应从头开始
int ch;
while ((ch = reader.read()) != -1) {
System.out.print((char) ch);
}
// 输出完整字符串 "Java I/O is powerful!"
}
}
}
}Reader 提供两个受保护的构造器,主要用于子类实现:
protected Reader()
// 同步锁为 this
protected Reader(Object lock)
// 使用指定对象作为同步锁,适用于组合多个流的场景普通开发者通常不需要直接调用这些构造器。
优先使用字符流处理文本:避免 FileInputStream + 手动转码导致的乱码
使用 try-with-resources:确保流在使用后自动关闭
需要按行读取?用 BufferedReader:
BufferedReader br = new BufferedReader(new FileReader("log.txt"));
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}指定编码更安全:FileReader 使用系统默认编码,跨平台可能出错。推荐:
Reader reader = new InputStreamReader(
new FileInputStream("file.txt"),
StandardCharsets.UTF_8
);Reader 是所有字符输入流的抽象基类,专为文本读取设计
核心方法包括 read()、close()、skip() 等
mark() / reset() 并非所有子类都支持(FileReader 不支持)
实际开发中常用 FileReader、BufferedReader、InputStreamReader
务必正确关闭资源,推荐使用 try-with-resources 语法
为什么 FileReader 不支持 mark() 和 reset()?哪些 Reader 子类支持?
如果一个文本文件使用 UTF-8 编码,但在 Windows 系统(默认 GBK)上用 FileReader 读取,可能出现什么问题?如何解决?
read(char[] cbuf) 和 read(char[] cbuf, int off, int len) 在性能和灵活性上有何区别?何时应使用后者?