Reader/Writer专用于字符数据,处理16位Unicode字符并自动编解码;读写纯文本且需控制字符集时应使用InputStreamReader/OutputStreamWriter显式指定编码,避免FileReader/FileWriter默认平台编码导致乱码。

Reader/Writer 专用于字符数据,不是文件操作万能替代
它们处理的是 char(16 位 Unicode 字符),底层自动完成字节到字符的解码/编码。如果你读写的是纯文本(如 JSON、XML、配置文件、日志行),且明确知道或需控制字符集(如 UTF-8、GBK),Reader/Writer 是合理选择;但若操作图片、音频、ZIP 包、序列化对象等二进制内容,必须用 InputStream/OutputStream —— 强行套用字符流会导致乱码或损坏。
常见错误:直接 new FileReader() 不指定编码,Windows 上读取 UTF-8 文件失败
FileReader 和 FileWriter 默认使用系统平台编码(如 Windows 的 GBK),遇到 UTF-8 编码的文本会出错。实际项目中应绕过这两个类,改用带显式编码的构造方式:
Reader reader = new InputStreamReader(new FileInputStream("data.txt"), "UTF-8");
Writer writer = new OutputStreamWriter(new FileOutputStream("out.txt"), "UTF-8");
- 永远优先用
InputStreamReader/OutputStreamWriter+ 显式编码名 - 避免用
FileReader/FileWriter,除非你 100% 确认系统默认编码匹配文件编码 - JDK 11+ 可用
Files.newBufferedReader(path, StandardCharsets.UTF_8),更简洁安全
BufferedReader.readLine() 是文本按行处理的事实标准
逐行读文本时,不要用 Reader.read(char[]) 自己拼接字符串——它不识别换行符边界,且对 \r\n、\n、\r 兼容性差。BufferedReader.readLine() 内部已处理所有平台换行变体,并自动丢弃换行符:
try (BufferedReader br = Files.newBufferedReader(Paths.get("log.txt"), StandardCharsets.UTF_8)) {
String line;
while ((line = br.readLine()) != null) {
// line 已是不含 \n\r 的干净字符串
}
}
-
readLine()返回null表示流结束,不是空行;空行返回空字符串"" - 它内部缓冲,默认 8192 字节,性能足够;无需额外包装
BufferedWriter也能高效写入 - 注意:它不保留原始换行符,如需原样处理(比如编辑器场景),得用
read()或read(char[])
Writer.flush() 和 close() 的区别常被忽略
flush() 强制把缓冲区内容写到底层输出目标(如磁盘文件),但流仍可继续写;close() 会先 flush() 再释放资源。漏掉 close() 可能导致最后几 KB 数据没落盘,尤其用在 FileWriter 或网络响应写入时:
立即学习“Java免费学习笔记(深入)”;
- 务必用 try-with-resources,它自动调用
close() - 手动管理时,
flush()适合“写一部分就确保可见”(如实时日志),但不能代替close() -
PrintWriter的println()默认不自动 flush,需构造时传true或手动调flush()
字符流的真正复杂点不在 API,而在编码一致性与资源生命周期——同一份文本在不同环节用了不同 Charset,或忘了 close 导致文件句柄泄漏,比语法错误更难定位。










