第十五章 IO流
2026/6/14 7:53:11 网站建设 项目流程

一、IO流基础概念

IO流是Java中实现数据传输的核心机制,位于java.io包下,本质是数据在内存与外部存储设备(如硬盘、网络)之间传输的“数据通道”,也被形象地称为“流”。

1. 流的核心分类方式

(1)按数据传输方向划分(以内存为参照物)

• 输入流:将外部设备中的数据读取到内存中,对应“读操作”,比如读取本地文件内容到程序中。

• 输出流:将内存中的数据写入到外部设备中,对应“写操作”,比如将程序中的字符串写入本地文件。

(2)按数据传输单位划分

• 字节流:以字节(1byte=8bit)为基本传输单位,可处理所有类型的文件(文本、图片、视频、音频等),是Java中最基础的IO流类型。

• 字符流:以字符为基本传输单位,仅能处理纯文本文件(如.txt、.java、.html等),底层本质仍是字节流+编码表,专门为解决文本文件的乱码问题而生。

(3)按流的功能角色划分

• 节点流:直接与数据源(文件、网络等)对接,具备最基础的读写功能,也被称为“基础流”,比如直接操作文件的FileInputStream。

• 处理流(过滤流):不直接对接数据源,而是在节点流的基础上进行封装,增强读写功能或提供额外特性,比如带缓冲功能的BufferedInputStream。
二、字节流详解

字节流的核心父类是两个抽象类:

• InputStream:所有字节输入流的父类,定义了read()系列读方法

• OutputStream:所有字节输出流的父类,定义了write()系列写方法

1. 常用节点字节流

(1)文件字节输出流:FileOutputStream

用于将内存中的数据写入本地文件,核心构造与用法:

• 路径形式:支持绝对路径(如D:/demo/test.txt)和相对路径(相对于项目根目录)

• 文件创建规则:指定文件不存在时,系统会自动创建;但上级目录不存在时,会抛出FileNotFoundException

• 追加写入设置:构造方法的第二个参数为true时,数据会追加到文件末尾;为false(默认)时会覆盖原文件内容

• 核心方法:

◦ write(int b):写入单个字节数据

◦ write(byte[] b):写入整个字节数组的数据

◦ write(byte[] b, int off, int len):写入字节数组中从下标off开始、长度为len的部分数据

◦ close():关闭流资源,释放系统占用

(2)文件字节输入流:FileInputStream

用于读取本地文件的数据到内存中,核心构造与用法:

• 文件存在性要求:指定文件不存在时,直接抛出FileNotFoundException,不会自动创建文件

• 核心方法:

◦ read():读取单个字节,返回读取到的字节值;读到文件末尾时返回-1

◦ read(byte[] b):读取数据到字节数组中,返回实际读取的字节数;读到文件末尾时返回-1

◦ read(byte[] b, int off, int len):读取数据到字节数组的指定区间,返回实际读取的字节数;读到文件末尾时返回-1

2. 常用处理字节流

(1)缓冲字节流:BufferedInputStream/BufferedOutputStream

• 核心优势:内置缓冲区,减少磁盘IO访问次数,大幅提升读写效率

• 关键特性:缓冲区满时会自动刷新,也可手动调用flush()方法强制刷新缓冲区;调用close()方法时会自动刷新并关闭流资源

• 典型应用:大文件的复制、传输场景,是文件上传下载的底层基础流

(2)数据字节流:DataInputStream/DataOutputStream

• 核心功能:直接读写Java的8种基本数据类型(byte、short、int、long、float、double、char、boolean),读写顺序需保持一致,否则会出现数据解析错误

• 典型应用:需要按指定格式存储基本数据类型的场景,比如自定义数据文件的读写

(3)对象字节流:ObjectInputStream/ObjectOutputStream

• 核心功能:实现Java对象的序列化与反序列化

◦ 序列化:将内存中的对象写入文件(或网络)中持久化存储

◦ 反序列化:将文件(或网络)中的对象数据读取到内存中重建对象

• 关键要求:参与序列化的对象对应的类必须实现java.io.Serializable接口(标记接口,无方法需实现),否则会抛出NotSerializableException

• 特殊规则:被transient修饰的属性不会参与序列化;自定义类的属性若包含其他自定义类型,该类型也需实现Serializable接口;集合类本身已实现序列化接口,但存储的自定义对象仍需实现该接口

• 异常处理:读取到文件末尾时会抛出EOFException,可通过该异常判断文件读取完成
三、字符编码与字符流

1. 常见字符编码方式

• ISO-8859-1:西欧编码,仅支持单字节字符,不支持中文

• GB2312/GBK/GB18030:中文编码体系,GB2312支持常用简体中文,GBK扩展支持更多汉字和繁体,GB18030覆盖所有中文字符,三者相互兼容

• Big5:繁体中文编码,主要用于港台地区

• UTF-8:万国码,采用动态字节存储,英文占1字节,中文占2-3字节,是目前最通用的编码方式

2. 编码与解码

• 编码:将字符(字符串)转换为对应编码格式的二进制数据的过程

• 解码:将二进制数据转换为对应编码格式的字符(字符串)的过程

• 关键注意:编码和解码必须使用相同的编码方式,否则会出现乱码问题

3. 字符流核心父类

• Reader:所有字符输入流的父类,定义了read()系列读方法

• Writer:所有字符输出流的父类,定义了write()系列写方法

4. 常用节点字符流

(1)文件字符输出流:FileWriter

• 核心用法与FileOutputStream类似,专门处理文本文件

• 核心方法:

◦ write(int c):写入单个字符数据

◦ write(String str):直接写入字符串数据

◦ write(char[] cbuf):写入整个字符数组的数据

(2)文件字符输入流:FileReader

• 核心用法与FileInputStream类似,专门处理文本文件

• 核心方法:

◦ read():读取单个字符,读到文件末尾返回-1

◦ read(char[] cbuf):读取数据到字符数组中,返回实际读取的字符数,读到文件末尾返回-1

5. 常用处理字符流

(1)缓冲字符流:BufferedReader/BufferedWriter

• 核心优势:内置字符缓冲区,提供按行读写的便捷方法,大幅提升文本文件读写效率

• 关键方法:

◦ BufferedReader.readLine():一次性读取一行文本,读到文件末尾时返回null

◦ BufferedWriter.newLine():写入一个平台无关的换行符,适配不同操作系统的换行格式

(2)打印字符流:PrintWriter

• 核心功能:提供便捷的打印方法,支持自动换行(println())和不换行(print()),可直接输出基本数据类型、字符串和对象(调用对象的toString()方法)

• 典型应用:文本文件的格式化输出、日志文件的写入场景

6. 转换流(桥接流)

• 核心类:InputStreamReader(字节转字符输入流)、OutputStreamWriter(字节转字符输出流)

• 核心作用:作为字节流和字符流之间的桥梁,可指定编码格式,解决文本文件读写的乱码问题

• 使用场景:当需要按指定编码方式读写文本文件时,需通过转换流实现

• 使用步骤:

1. 创建节点字节流对象(如FileInputStream/FileOutputStream)

2. 创建转换流对象,将字节流包装为字符流,并指定编码格式

3. 可选:用处理流(如BufferedReader/PrintWriter)包装转换流,增强读写功能

4. 执行读写操作

5. 关闭流资源(只需关闭最外层的流,内层流会自动关闭)
四、File类详解

File类位于java.io包下,专门用于对文件或目录本身进行操作,与IO流的区别是:IO流操作的是文件的内容,而File类操作的是文件/目录的属性和状态。

1. File类常用方法

• getName():获取文件/目录的名称(含后缀名)

• getAbsolutePath():获取文件/目录的绝对路径

• isFile():判断当前对象是否为文件

• isDirectory():判断当前对象是否为目录

• listFiles():获取当前目录下所有的文件和子目录,返回File数组

• delete():删除文件或空目录

• mkdir()/mkdirs():创建单级目录/多级目录

2. 典型应用:遍历目录文件

通过递归遍历指定目录下的所有文件,可实现批量处理文件的需求,例如筛选出所有.java文件:
public static void listJavaFiles(File dir) {
// 获取目录下所有文件和子目录
File[] files = dir.listFiles();
if (files != null) {
for (File file : files) {
if (file.isFile()) {
// 判断文件是否为.java文件
if (file.getName().endsWith(".java")) {
System.out.println("找到Java文件:" + file.getAbsolutePath());
}
} else if (file.isDirectory()) {
// 递归遍历子目录
listJavaFiles(file);
}
}
}
}
五、IO流核心总结

1. 流的选择原则:处理文本文件优先用字符流,处理其他类型文件必须用字节流;需要高效读写优先用缓冲流,需要序列化对象必须用对象流,需要指定编码格式需用转换流。

2. 流的关闭规则:所有IO流使用后都需调用close()方法释放资源,建议在try-finally块中关闭流,或使用try-with-resources语法自动关闭流。

3. 序列化关键注意:对象序列化必须实现Serializable接口,transient修饰的属性不参与序列化,反序列化时类的结构需与序列化时保持一致,否则会抛出异常。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询