粮草机器人 在 Windows 操作系统下使用 JDK 8 时,FileReader 是 Java IO 包中用于读取字符文件的便捷类
在 Windows 操作系统下使用 JDK 8 时,FileReader 是 Java IO 包中用于读取字符文件的便捷类。
以下是对 FileReader 的源码结构、工作原理及具体使用方法的详细分析。
1. FileReader 源码结构与继承关系
FileReader 本身是一个非常轻量的类,它并没有实现复杂的读取逻辑,而是通过继承体系复用父类的功能。
继承 hierarchy
java
public class FileReader extends InputStreamReader
直接父类:InputStreamReader(字节流到字符流的桥梁)。
间接父类:Reader(所有字符输入流的抽象基类)。
实现接口:Closeable, AutoCloseable, Readable。
核心源码分析(JDK 8)
在 JDK 8 中,FileReader 的主要代码仅包含几个构造方法。其核心逻辑在于构造时内部创建了一个 FileInputStream,并将其传递给父类 InputStreamReader。
java
package java.io;
import java.nio.charset.Charset;
public class FileReader extends InputStreamReader {
// 构造方法 1:通过文件路径字符串创建
public FileReader(String fileName) throws FileNotFoundException {
super(new FileInputStream(fileName));
}
// 构造方法 2:通过 File 对象创建
public FileReader(File file) throws FileNotFoundException {
super(new FileInputStream(file));
}
// 构造方法 3:通过文件描述符创建
public FileReader(FileDescriptor fd) {
super(new FileInputStream(fd));
}
}
关键点解析:
本质是字节流转换:FileReader 内部持有一个 FileInputStream 实例。它先以字节形式从硬盘读取数据,然后通过 InputStreamReader 将字节解码为字符。
默认编码陷阱:注意上述构造方法中,调用 super(...) 时没有指定字符集。这意味着它使用平台默认字符集进行解码。
在 Windows 系统上,JDK 8 的默认字符集通常是 GBK (或 GB2312/CP936)。
如果读取的文件是 UTF-8 编码,而系统默认是 GBK,直接使用 FileReader 会导致中文乱码。
2. 主要使用方法
由于 FileReader 继承了 InputStreamReader 和 Reader,它可以使用以下核心方法读取数据:
表格
方法签名 说明
int read() 读取单个字符,返回字符的 Unicode 值,到达流末尾返回 -1。
int read(char[] cbuf) 将字符读入数组,返回读取的字符数,到达末尾返回 -1。
int read(char[] cbuf, int off, int len) 将字符读入数组的一部分,效率较高,推荐用于大文件。
void close() 关闭流并释放资源。
3. 代码示例
示例 1:基础读取(逐个字符)
适用于小文件或测试,效率较低。
java
import java.io.FileReader;
import java.io.IOException;
public class FileReaderDemo1 {
public static void main(String[] args) {
// 假设 test.txt 是 GBK 编码(Windows 默认新建文本文件通常为 ANSI/GBK)
FileReader fr = null;
try {
fr = new FileReader("test.txt");
int ch;
// read() 返回 int,需要强转为 char 才能显示正确字符
while ((ch = fr.read()) != -1) {
System.out.print((char) ch);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fr != null) {
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
示例 2:高效读取(字符数组缓冲)
推荐方式,减少 IO 次数。
java
import java.io.FileReader;
import java.io.IOException;
public class FileReaderDemo2 {
public static void main(String[] args) {
FileReader fr = null;
try {
fr = new FileReader("test.txt");
char[] buffer = new char; // 1KB 缓冲区
int len;
while ((len = fr.read(buffer)) != -1) {
// 注意:只打印实际读取到的长度,避免打印缓冲区残留数据
System.out.print(new String(buffer, 0, len));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fr != null) fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
示例 3:使用 try-with-resources(JDK 7+ 推荐)
自动管理资源关闭,代码更简洁安全。
java
import java.io.FileReader;
import java.io.IOException;
public class FileReaderDemo3 {
public static void main(String[] args) {
// try 括号内声明的资源会在 try 块结束后自动关闭
try (FileReader fr = new FileReader("test.txt")) {
char[] buffer = new char;
int len;
while ((len = fr.read(buffer)) != -1) {
System.out.print(new String(buffer, 0, len));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
4. Windows 环境下的关键注意事项
1. 编码乱码问题
这是 FileReader 在 Windows 上最大的痛点。
现象:如果文件是用 UTF-8 保存的(例如现代编辑器默认格式),而你在 Windows JDK 8 上使用 new FileReader("utf8_file.txt"),读取出的中文会变成乱码。
原因:FileReader 强制使用 Charset.defaultCharset(),Windows 下通常为 GBK。
解决方案:如果需要指定编码(如 UTF-8),不要直接使用 FileReader,而应使用 InputStreamReader 包装 FileInputStream:
java
// 正确读取 UTF-8 文件的方式
try (InputStreamReader isr = new InputStreamReader(
new FileInputStream("utf8_file.txt"), "UTF-8")) {
// 使用 isr 进行读取...
}
2. 换行符处理
Windows 系统的换行符是 \r\n。
FileReader 的 read() 方法会原样读取这些字符。如果你逐字符读取并打印,可能会看到额外的空行或控制字符行为,具体取决于控制台如何处理 \r。通常使用 BufferedReader 包装 FileReader 并使用 readLine() 可以屏蔽不同操作系统的换行差异。
3. 文件路径
在 Windows 上,文件路径分隔符可以是 \ 或 /。但在 Java 字符串中,反斜杠 \ 需要转义为 \\。
推荐使用正斜杠 / 或 File.separator 以保证跨平台兼容性,尽管在纯 Windows 环境下 \ 也能工作。
总结
适用场景:FileReader 适合读取已知编码与平台默认编码一致(在 Windows 上即 GBK/ANSI)的文本文件。
不适用场景:读取二进制文件(图片、视频等)应使用 FileInputStream;读取非平台默认编码(如 UTF-8)的文本文件,建议使用 InputStreamReader + FileInputStream 组合。
最佳实践:始终配合 BufferedReader 使用以提高效率,并使用 try-with-resources 确保资源释放。