Skip to content

IO 流体系结构

Java 有几十个 IO 类,继承关系看似复杂,其实只有两条主线:字节流和字符流。搞清楚继承关系,你就能举一反三——学会一个类,其他类自然就会了。

字节流体系

java.lang.Object

    └── java.io.InputStream(抽象类)

            ├── FileInputStream          文件字节输入流(节点流)
            ├── ByteArrayInputStream     字节数组输入流(节点流)
            ├── PipedInputStream         管道输入流(线程间通信)
            ├── FilterInputStream        过滤输入流(装饰器基类)
            │       ├── BufferedInputStream       加缓冲
            │       ├── DataInputStream           读基本类型
            │       └── ObjectInputStream         读对象
            └── SequenceInputStream      合并多个输入流
java.lang.Object

    └── java.io.OutputStream(抽象类)

            ├── FileOutputStream         文件字节输出流(节点流)
            ├── ByteArrayOutputStream    字节数组输出流(节点流)
            ├── PipedOutputStream        管道输出流(线程间通信)
            ├── FilterOutputStream       过滤输出流(装饰器基类)
            │       ├── BufferedOutputStream       加缓冲
            │       ├── DataOutputStream            写基本类型
            │       ├── ObjectOutputStream          写对象
            │       └── PrintStream                 打印流(最常用)
            └── StreamTokenizer          字符串解析器

字符流体系

java.lang.Object

    └── java.io.Reader(抽象类)

            ├── InputStreamReader        字节→字符转换流
            │       └── FileReader       文件字符输入流(便捷类,但默认编码有坑)
            ├── CharArrayReader          字符数组输入流(节点流)
            ├── StringReader             字符串输入流(节点流)
            ├── PipedReader              管道字符输入流
            ├── BufferedReader           缓冲字符输入流(处理流 + readLine())
            └── LineNumberReader         带行号的 BufferedReader
java.lang.Object

    └── java.io.Writer(抽象类)

            ├── OutputStreamWriter       字符→字节转换流
            │       └── FileWriter       文件字符输出流(便捷类,但默认编码有坑)
            ├── CharArrayWriter          字符数组输出流(节点流)
            ├── StringWriter             字符串输出流(节点流)
            ├── PipedWriter              管道字符输出流
            ├── BufferedWriter           缓冲字符输出流(处理流 + newLine())
            └── PrintWriter              打印流(字符版,比 PrintStream 更推荐)

NIO 体系

java.nio.channels.Channel(接口)

    ├── SelectableChannel(可注册到 Selector)
    │       ├── SocketChannel           TCP 客户端通道
    │       ├── ServerSocketChannel     TCP 服务端通道
    │       ├── DatagramChannel         UDP 通道
    │       └── Pipe.SinkChannel / Pipe.SourceChannel  管道通道
    └── FileChannel                     文件通道(不能注册到 Selector)
java.nio.Buffer(抽象类)

    ├── ByteBuffer                       字节缓冲区(最常用)
    ├── CharBuffer                       字符缓冲区
    ├── ShortBuffer / IntBuffer / LongBuffer
    ├── FloatBuffer / DoubleBuffer
    └── MappedByteBuffer                内存映射缓冲区

装饰器模式:为什么类这么多

Java IO 类众多的核心原因:装饰器模式

核心思想:把功能一层一层地「包」上去。

java
// 基础版:能跑,但慢
InputStream in = new FileInputStream("data.bin");

// 加缓冲:减少系统调用,快几十倍
InputStream in = new BufferedInputStream(
    new FileInputStream("data.bin"));

// 加数据类型:能读 int/double
DataInputStream in = new DataInputStream(
    new BufferedInputStream(
        new FileInputStream("data.bin")));

// 加对象:能读对象
ObjectInputStream in = new ObjectInputStream(
    new BufferedInputStream(
        new FileInputStream("data.bin")));

每个「装饰器」只加一个功能,可以自由组合。

最常用的组合

场景推荐组合
读二进制文件BufferedInputStream + FileInputStream
写二进制文件BufferedOutputStream + FileOutputStream
读文本文件BufferedReader + InputStreamReader(指定 UTF-8)
写文本文件BufferedWriter + OutputStreamWriter(指定 UTF-8)
读对象ObjectInputStream + BufferedInputStream
打印日志PrintWriterPrintStream

记住这个口诀:字节字符是两条线,节点处理是装饰器,永远记得包 Buffered

下一步

基于 VitePress 构建