上一篇我们吃透了File类——这个文件/目录的“万能遥控器”,但它只能搞定路径和属性,没法操作文件里的内容。而Java IO流(Input/Output Stream)就是专门用来“读写内容”的工具集,像连接程序与文件、网络的“数据管道”,负责把数据搬进搬出。今天就带大家拆解IO流的体系结构,分清字节流与字符流的区别,搞定各类流的使用场景!

先划核心认知:IO流的核心是“按数据单位分类”,分为字节流(以字节为单位,处理所有数据)和字符流(以字符为单位,仅处理文本数据),两大体系各自有完整的抽象类和实现类,按需选用即可。

一、IO流整体体系结构

Java IO流的设计遵循“抽象定义+具体实现”的原则,顶层是4个抽象类,所有具体流都继承或实现这些抽象类,结构清晰且易于扩展。整体体系可归纳为以下表格,覆盖常用核心流类:

流类型

输入流(读数据)

输出流(写数据)

核心特点

字节流(byte stream)

InputStream(抽象类)├─ FileInputStream(文件输入字节流)└─ BufferedInputStream(缓冲输入字节流)

OutputStream(抽象类)├─ FileOutputStream(文件输出字节流)└─ BufferedOutputStream(缓冲输出字节流)

以1字节(8位)为单位读写可处理所有数据(文本、图片、视频等)无编码依赖

字符流(character stream)

Reader(抽象类)├─ FileReader(文件输入字符流)└─ BufferedReader(缓冲输入字符流)

Writer(抽象类)├─ FileWriter(文件输出字符流)└─ BufferedWriter(缓冲输出字符流)

以1字符(16位)为单位读写仅处理文本数据(依赖编码格式)避免中文乱码问题

注意:不存在“BufferedFileReader”类,正确类名为BufferedReader(装饰器模式,包装Reader子类),很多新手会混淆这一点,需特别留意!

二、字节流体系:万能的数据搬运工

字节流是IO流的基础,不管是文本、图片、音频还是视频,字节流都能处理——因为所有数据在计算机中本质都是字节。核心顶层抽象类是InputStream(读)和OutputStream(写),我们重点掌握常用实现类。

1. 基础文件字节流:FileInputStream & FileOutputStream

直接对接文件,负责从文件读字节、向文件写字节,是最基础的文件读写流。

代码示例:用字节流复制一张图片(万能复制,适用于所有文件)

核心说明:read(buffer)将数据读入字节数组,返回实际读取的字节数;write(buffer, 0, len)精准写入有效数据,避免浪费资源。

2. 缓冲字节流:BufferedInputStream & BufferedOutputStream

基础字节流每次读写都直接操作硬盘,效率极低。缓冲流通过“内存缓冲区”优化:读取时先把数据缓存到内存,写入时先存缓冲区,满了再一次性写入硬盘,大幅减少硬盘IO次数。

代码示例:用缓冲字节流优化文件复制

优势:缓冲流的读写效率比基础字节流高10倍以上,处理大文件时差距尤为明显,日常开发优先使用。

三、字符流体系:文本数据的专属翻译官

字节流处理文本时,需要手动转换字节与字符,容易出现中文乱码(因编码格式差异)。字符流底层自动完成“字节→字符”的编码转换,专门适配文本文件(.txt、.java等),核心顶层抽象类是Reader(读)和Writer(写)。

1. 基础文件字符流:FileReader & FileWriter

直接对接文本文件,按字符读写,默认使用系统编码(Windows是GBK,Linux/Mac是UTF-8),适合简单文本操作。

代码示例:用字符流读写文本文件

2. 缓冲字符流:BufferedReader & BufferedWriter

类似缓冲字节流,缓冲字符流也有内存缓冲区,同时提供了专属优化方法:BufferedReader.readLine()按行读取文本,BufferedWriter.newLine()跨平台换行(自动适配Windows\n\r、Linux\n),是文本处理的首选。

代码示例:用缓冲字符流按行读写文本

四、字节流vs字符流:怎么选才不踩坑?

很多新手纠结选字节流还是字符流,记住核心原则:按处理的数据类型决定,结合场景优化效率。

  • 选字节流的场景:处理非文本数据(图片、视频、音频、压缩包等);需要精准控制字节(如文件分片上传);不确定数据类型时(字节流是万能选择)。

  • 选字符流的场景:处理文本数据(.txt、.md、配置文件等);需要按行读写、避免中文乱码;追求文本操作的简洁性。

  • 必用缓冲流:无论字节流还是字符流,日常开发都优先用对应的缓冲流(BufferedXXX),效率远超基础流,且用法几乎一致(仅包装一层即可)。

五、避坑小贴士

  1. 流的关闭顺序:如果同时打开多个流(如缓冲流包装基础流),关闭外层流即可(内层流会被自动关闭);手动关闭时需“后打开先关闭”,避免资源泄露。

  2. 编码问题:FileReader/FileWriter默认用系统编码,可能导致跨平台乱码,推荐用InputStreamReader/OutputStreamWriter(转换流)指定编码(如UTF-8)。

  3. 缓冲区刷新:缓冲流的write()不会立即写入硬盘,需调用flush()手动刷新,或等待close()自动刷新(关闭前务必确保数据刷入)。

  4. try-with-resources语法:JDK7+推荐使用该语法,自动关闭实现AutoCloseable接口的流对象,无需手动写finally关闭,代码更简洁。

总结

Java IO流体系的核心是“字节流通用,字符流专属文本”,4个顶层抽象类(InputStream、OutputStream、Reader、Writer)定义了基本行为,具体实现类负责落地,缓冲流负责优化效率。

记住:处理文件先靠File类定位路径,再用IO流读写内容;非文本用字节缓冲流,文本用字符缓冲流,按场景选择就能高效避坑。后续我们还会拓展转换流、序列化流、打印流等进阶内容,逐步吃透Java IO全家桶!

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐