# 阶段五:IO 流与文件操作 —— 核心知识点总纲 > 本阶段涵盖:**File 文件操作与 IO 流入门、IO 缓冲流与字符流、转换流与对象序列化** > 细分文档:`按日细分/20260806-笔记.md`、`按日细分/20260807-笔记.md`、`按日细分/20260808-笔记.md`(转换流/序列化部分) > 学生需要重点理解、背诵、掌握的理论核心知识点。 --- ## 一、File 文件操作类(对应 08-06) ### 概念 `File` 是**文件和目录路径名的抽象表示**——**不一定是真实存在的文件,只是一个路径名**。File **只描述路径、不做真正的读写**(真正读写用 IO 流)。 ### 三种构造方法 ```java new File(String pathname) new File(String parent, String child) new File(File parent, String child) ``` ### 路径概念 - 分隔符:Windows `\`;Linux/UNIX `/` - 绝对路径:从盘符/根目录开始(快递地址);相对路径:相对某位置(前后左右) ### 常用方法(必背) | 分类 | 方法 | |------|------| | 创建 | `createNewFile()`(抛 IOException)/ `mkdir()` / `mkdirs()`(多级) | | 删除 | `delete()` | | 判断 | `isFile()` / `isDirectory()` / `exists()` | | 获取 | `getAbsolutePath()` / `getPath()` / `getName()` / `listFiles()`(File[] 数组) | ## 二、IO 流基础概念(对应 08-06) ### 分类(两个维度必背) | 维度 | 类别 | |------|------| | 按数据流向 | 输入流(读)、输出流(写) | | 按数据类型 | **字节流**(byte)、**字符流**(char) | ### 使用场景推荐(必背) - **纯文本(.txt)**:字符流(1 字符 = 2 字节) - **其他任何文件**(图片/视频/Word 等):字节流 - **不确定类型**:字节流 ### 字节流两大抽象父类 - `OutputStream` / `InputStream`;子类名以父类名作后缀(FileOutputStream、FileInputStream) ## 三、字节流读写(对应 08-06) ### FileOutputStream(输出) **使用三步:①创建流对象 ②调用写方法 ③关闭流** - 构造:`(File)` / `(String)` / `(File, append)` / `(String, append)`——`append=true` 追加否则覆盖 - 写方法:`write(int b)` / `write(byte[] b)` / `write(byte[] b, off, len)` - 字符串写入前先 `getBytes()` - 换行符:Linux `\n`;Windows `\r\n`;macOS `\r` ### FileInputStream(输入) **使用三步:①创建流对象 ②调用读方法 ③关闭流** - 读方法:`read()` / `read(byte[] b)` / `read(byte[] b, off, len)` - **关键返回值**:`read()` 返回 **-1 表示 EOF**;`read(byte[])` 返回**本次有效长度** **经典循环读写法(必背):** ```java FileInputStream fis = new FileInputStream("E:/我的文件.txt"); byte[] bytes = new byte[1024]; int length; while ((length = fis.read(bytes)) != -1) { System.out.println(new String(bytes, 0, length, Charset.forName("UTF-8"))); } fis.close(); ``` > 用 **try-catch-finally** 关闭资源,finally 保证 close()。 ### 文件复制(输入 + 输出配合) ```java byte[] bytes = new byte[4096]; // 缓冲区思想:一次读/写一批 int length; while ((length = fis.read(bytes)) != -1) { fos.write(bytes, 0, length); // 只写本次有效字节 } fos.close(); // 先关输出流,再关输入流 fis.close(); ``` > 缓冲区越大、磁盘 I/O 越少、效率越高。耗时统计用 `System.currentTimeMillis()`。 ## 四、缓冲流与字符流(对应 08-07) ### 1. 面向接口编程(CopyFile 接口) 接口定义复制规范,多种实现(普通字节流 vs 缓冲流),调用方只依赖接口——**多态可随时替换**。 ### 2. 字节缓冲流(必背) - `BufferedOutputStream` / `BufferedInputStream`:**包装流/装饰流**,给底层字节流加缓冲 - **减少磁盘 I/O 次数**,显著提升效率;默认缓冲区 8192 字节(8KB) - 构造参数是底层流:`new BufferedOutputStream(fos)` ### 3. 基础流 vs 扩展流(必背) - **基础流**(FileInputStream/FileOutputStream)**直接操作文件**——数据源头与终点 - **扩展流**(缓冲流)**不直接操作文件**,用来**操作基础流**——叠加增强能力 **包装流程**:先建文件流 → 缓冲流包装 → 操作缓冲流 → 关闭(先关缓冲再关底层) ### 4. flush() 刷新(必背) 缓冲流默认**缓冲区满了才落盘**;`flush()` 手动强制刷新。 > close() 之前会自动 flush 一次;flush 用于"不关闭流但需及时看到数据"。 ### 5. 字符流(必背) **字符流 = 字节流 + 字符集编码表**——解决字节流操作中文不方便的问题。 **字符集:** ASCII / GB-2312 / GBK / Unicode(UTF-8) - **编码**:`字符串.getBytes()`(字符串 → 字节) - **解码**:`new String(byte[])`(字节 → 字符串) **字符流体系:** ``` Reader(输入字符流抽象类)→ FileReader Writer(输出字符流抽象类)→ FileWriter ``` **字符流核心优势(必背):** - **可直接 `write(String)` 写字符串,无需 getBytes()**——操作中文方便 - **自带缓冲区**,写后需 `flush()` - `read()` 返回 -1 表示 EOF;`read(char[])` 返回有效字符数 - 构造可指定字符集(Charset)解决乱码 ### 6. 字符缓冲流(必背) | 流 | 特有方法 | 说明 | |----|----------|------| | `BufferedWriter` | `newLine()` | 写**跨平台行分隔符** | | `BufferedReader` | `readLine()` | 读一行(不含终止符),**EOF 返回 null** | **经典逐行读(必背):** ```java BufferedReader br = new BufferedReader(new FileReader("D:/scores.txt")); String line; while ((line = br.readLine()) != null) { ... } br.close(); ``` ### 7. IO 流体系总览(必背) ``` 基础流: 字节流:InputStream → FileInputStream / OutputStream → FileOutputStream 字符流:Reader → FileReader / Writer → FileWriter 处理流(扩展流)- 缓冲流: 缓冲字节流:BufferedInputStream / BufferedOutputStream 缓冲字符流:BufferedReader / BufferedWriter ``` **选型口诀**:不确定用字节流;纯文本用字符流;要效率加缓冲流。 ## 五、转换流与对象序列化(对应 08-08) ### 1. 转换流(字符集转码必背) **乱码根源**:同一字节在不同字符集含义不同——用 A 编码、用 B 解码就乱码。 模型:`字符 --编码--> 字节 --解码--> 字符` | 桥梁 | 父类 | 方向 | 动作 | |------|------|------|------| | `InputStreamReader` | Reader | **字节 → 字符** | **解码** | | `OutputStreamWriter` | Writer | **字符 → 字节** | **编码** | ```java new InputStreamReader(new FileInputStream("D:/abc.txt"), "UTF-8"); // 读端指定源编码 new OutputStreamWriter(new FileOutputStream("D:/hello.txt"), "GBK"); // 写端指定目标编码 ``` ### 2. 对象序列化(必背) **对象持久化**:把内存对象保存到磁盘 / 网络传输——本质是把对象变成**字节序列**(含类型、数据、属性)。 ``` 序列化:对象 --ObjectOutputStream.writeObject()--> 字节序列 --> 文件 反序列化:文件 --ObjectInputStream.readObject()--> 字节序列 --> 内存重构对象 ``` - **必须实现 `Serializable` 接口**(标记接口:无方法无属性,仅作"可序列化"标识) - `readObject()` 返回 Object,需**强转**;抛 `ClassNotFoundException` ### 3. serialVersionUID(必背) - 序列化后修改类结构(增删属性),再反序列化抛 `InvalidClassException` - **解决**:显式声明 `private static final long serialVersionUID = 42L;` - 作用:①验证版本一致性 ②未声明时 JVM 按类结构自动生成 ③类结构变 → 版本号变 → 报错 - **最佳实践**:实现 Serializable 的类都显式声明(值无所谓,两端一致即可) ### 4. transient(必背) `transient` 修饰的成员**不参与序列化**,反序列化为默认值(引用 null)。 ### 5. 序列化 6 条注意事项(必背) 1. **静态属性不序列化**(属于类,不属于对象) 2. transient 属性不序列化 3. **父类实现 Serializable → 子类自动可序列化** 4. **反序列化不调用构造方法** 5. **引用链上所有对象必须可序列化**(否则 NotSerializableException) 6. 单例对象需重写 `readResolve()` ### 6. IO 流体系总结(必背) ``` 基础流:字节流(FileInputStream/FileOutputStream)、字符流(FileReader/FileWriter) 处理流:缓冲流(BufferedInputStream/OutputStream、BufferedReader/Writer) 转换流(InputStreamReader 解码 / OutputStreamWriter 编码) 对象流(ObjectOutputStream 序列化 / ObjectInputStream 反序列化) ``` - 四个通用方法:write / read / flush / close - 特殊方法:readLine/newLine(缓冲字符流)、writeObject/readObject(对象流) - 特殊属性:serialVersionUID;特殊关键字:transient ## 本阶段必须背诵的核心口诀 1. **File 只管路径,不真正读写;读写用 IO 流** 2. **IO 流三步走:创建 → 读写 → 关闭** 3. **纯文本字符流、其他字节流、不确定用字节流** 4. **read() 返回 -1 = EOF;read(byte[]) 返回有效长度** 5. **文件复制 = 输入流读 + 输出流写 + 缓冲区循环** 6. **缓冲流 = 包装流,减少磁盘 I/O;基础流直接操作文件** 7. **字符流可直接 write(String),自带缓冲区要 flush** 8. **readLine() 一次读一行、EOF 返回 null;newLine() 跨平台换行** 9. **转换流:Input 解码(字节→字符)、Output 编码(字符→字节)** 10. **序列化必须实现 Serializable;serialVersionUID 防类结构变化报错;transient 跳过序列化** 11. **流用完必须 close()(先关外层再关底层),finally 或 try-with-resources 保证**