Java IO 流与 Reader

字节流与字符流的职责分层、装饰器组合,以及读写时的编码与缓冲实践。

#type / concept #status / growing #tech / dev #resource / java

[!info] 关联笔记

Java IO 流与 Reader

这个概念为什么出现

文件、网络、进程管道最终都是字节;人类文本还涉及字符编码。Java 经典 IO 分成字节流InputStream/OutputStream)与字符流Reader/Writer),并用装饰器叠加缓冲、转换等能力。

[!abstract] 一句话理解 字节流处理原始字节;字符流在 Reader/Writer 层处理文本;用 InputStreamReader 等桥接并显式指定 Charset,缓冲装饰器减少系统调用。

最小可运行示例

场景:读取 UTF-8 配置行并写出备份

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;

public class ConfigLineCopy {
    static void copyFirstLine(Path src, Path dst) throws IOException {
        try (BufferedReader r = Files.newBufferedReader(src, StandardCharsets.UTF_8);
             BufferedWriter w = Files.newBufferedWriter(dst, StandardCharsets.UTF_8)) {
            String line = r.readLine();
            if (line != null) {
                w.write(line);
                w.newLine();
            }
        }
    }
    public static void main(String[] args) throws Exception {
        Path src = Files.createTempFile("cfg-", ".txt");
        Path dst = Files.createTempFile("cfg-bak-", ".txt");
        Files.writeString(src, "mode=prod\n", StandardCharsets.UTF_8);
        copyFirstLine(src, dst);
        System.out.println(Files.readString(dst, StandardCharsets.UTF_8).trim());
        Files.deleteIfExists(src);
        Files.deleteIfExists(dst);
    }
}

建议运行:

javac ConfigLineCopy.java && java ConfigLineCopy

期望输出:

mode=prod

结合场景再看三个关注点

  1. 文本用 Reader/Writer + Charset
  2. 缓冲是装饰能力,不是另一种数据模型。
  3. TWR 保证关闭,关闭通常会 flush 写出流。

核心概念与准确模型

1. 字节流

  • InputStream.read 返回 0–255 或 -1 EOS
  • 适合图片、protobuf、加密 blob

2. 字符流

  • Reader 以 char 为逻辑单位
  • InputStreamReader 负责字节→字符解码

3. 装饰器组合

FileInputStream → BufferedInputStream → ...
InputStreamReader → BufferedReader

4. 现代便捷入口

  • Files.newBufferedReader/Writer
  • Files.readString/writeString(小文件)

边界情况与反直觉行为

  1. 默认 charset 方法危险。
  2. 以 byte 读文本易截断多字节字符。
  3. 大文件避免一次 readAllBytes

常见误区

[!warning] 常见误区:二进制当字符流读 压缩包/图片用字节流,否则编码破坏数据。

工程实践

  1. 统一 UTF-8。
  2. 缓冲区大小按场景,不玄学调参。
  3. 网络 IO 设超时(更高层 API)。
  4. 优先 NIO.2 Path/Files 管理文件路径。

本节总结

  • 字节 vs 字符是第一刀
  • 装饰器组合能力
  • 编码显式 + 资源关闭

自测题

  1. 何时必须用 InputStream 而不是 Reader?
  2. BufferedReader 解决什么?
参考答案
  1. 非文本字节数据或需精确字节协议时。
  2. 按行高效读取与减少底层读取次数。

延伸阅读与资料来源

资料类型支撑内容
I/O Streams (Oracle Tutorial)教程流模型
java.io packageAPI类型入口
创建于 2026/7/15 更新于 2026/7/15