阶段05-IO流与文件操作.md 9.6 KB

阶段五:IO 流与文件操作 —— 核心知识点总纲

本阶段涵盖:File 文件操作与 IO 流入门、IO 缓冲流与字符流、转换流与对象序列化 细分文档:按日细分/20260806-笔记.md按日细分/20260807-笔记.md按日细分/20260808-笔记.md(转换流/序列化部分) 学生需要重点理解、背诵、掌握的理论核心知识点。


一、File 文件操作类(对应 08-06)

概念

File文件和目录路径名的抽象表示——不一定是真实存在的文件,只是一个路径名。File 只描述路径、不做真正的读写(真正读写用 IO 流)。

三种构造方法

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 表示 EOFread(byte[]) 返回本次有效长度

经典循环读写法(必背):

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()。

文件复制(输入 + 输出配合)

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

经典逐行读(必背):

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 字符 → 字节 编码
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 保证