非常好,下面我将根据你提供的《第12章 Java输入输出流》的完整内容,重新系统梳理并整理成一份结构清晰、逻辑严谨、便于复习和查阅的笔记文档。
📘 第12章:Java 输入输出流(I/O)知识点总结
一、I/O 基本概念
✅ 什么是 I/O?
- Input/Output(输入/输出) 是程序与外部设备或网络之间进行数据交换的过程。
- Java 使用"流(Stream)"的方式处理 I/O 操作,抽象为一个流动的数据管道。
✅ Java I/O 的发展历程:
| 版本 | 功能 |
|---|---|
| JDK 1.0 | 面向字节的 I/O 流(InputStream / OutputStream) |
| JDK 1.1 | 引入面向字符的 I/O 流(Reader / Writer) |
| JDK 1.4 | 新增 java.nio 包,提升性能和功能 |
| JDK 7+ | 支持 try-with-resources 自动关闭资源机制 |
二、Java 流的分类
| 分类方式 | 类型 | 描述 |
|---|---|---|
| 按方向 | 输入流 / 输出流 | 数据从源读取或写入目标 |
| 按单位 | 字节流 / 字符流 | 以字节(8位)或字符(16位 Unicode)为单位 |
| 按功能 | 节点流 / 处理流 | 节点流直接操作物理存储;处理流增强节点流的功能 |
三、字节流体系
🔹 抽象类:InputStream 和 OutputStream
InputStream接口与主要方法:
int read(): 读取单个字节,返回0-255的整数,如果到达末尾返回-1int read(byte[] b): 读取多个字节到缓冲区,返回实际读取的字节数int read(byte[] b, int off, int len): 读取指定长度到缓冲区指定位置void close(): 关闭流并释放资源long skip(long n): 跳过n个字节int available(): 返回不阻塞的情况下可读取的字节数
OutputStream接口与主要方法:
void write(int b): 写入单个字节void write(byte[] b): 写入字节数组void write(byte[] b, int off, int len): 写入部分字节数组void flush(): 刷新缓冲区void close(): 关闭流并释放资源
1. InputStream 主要子类:
FileInputStream:从文件中读取字节ByteArrayInputStream:从内存缓冲区读取字节PipedInputStream:用于线程间通信SequenceInputStream:合并多个流为一个流
2. OutputStream 主要子类:
FileOutputStream:向文件写入字节ByteArrayOutputStream:在内存中收集字节PipedOutputStream:用于线程间通信
示例:使用 FileInputStream + FileOutputStream 实现文件复制
java
try (FileInputStream fis = new FileInputStream("input.txt");
FileOutputStream fos = new FileOutputStream("output.txt")) {
int data;
while ((data = fis.read()) != -1) {
fos.write(data);
}
} catch (IOException e) {
e.printStackTrace();
}🔹 缓冲流:BufferedInputStream 和 BufferedOutputStream
接口特性:
- 继承自
FilterInputStream和FilterOutputStream - 默认缓冲区大小为8KB,可通过构造函数设置
- 显著提高I/O操作性能,减少系统调用次数
BufferedInputStream主要方法:
- 继承
InputStream的所有方法 void mark(int readlimit): 标记当前位置void reset(): 重置到上次标记位置boolean markSupported(): 是否支持标记功能
BufferedOutputStream主要方法:
- 继承
OutputStream的所有方法 void flush(): 重写以刷新缓冲区数据到底层流
示例:带缓冲的文件复制
java
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("input.bin"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("output.bin"))) {
int data;
while ((data = bis.read()) != -1) {
bos.write(data);
}
} catch (IOException e) {
e.printStackTrace();
}🔹 数据过滤流:DataInputStream 和 DataOutputStream
接口特性:
- 实现了
DataInput和DataOutput接口 - 用于按基本数据类型读写(int, double, boolean 等)
- 必须配合使用,不能混用普通文本流
DataInputStream主要方法:
readBoolean(),readByte(),readChar(),readDouble(),readFloat()readInt(),readLong(),readShort(),readUTF()skipBytes(int n): 跳过指定字节数
DataOutputStream主要方法:
writeBoolean(),writeByte(),writeChar(),writeDouble(),writeFloat()writeInt(),writeLong(),writeShort(),writeUTF()size(): 返回已写入的字节数
示例:
java
// 写入
try (DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.bin"))) {
dos.writeInt(100);
dos.writeDouble(3.14);
dos.writeUTF("Hello");
}
// 读取
try (DataInputStream dis = new DataInputStream(new FileInputStream("data.bin"))) {
System.out.println(dis.readInt()); // 100
System.out.println(dis.readDouble()); // 3.14
System.out.println(dis.readUTF()); // Hello
}🔹 打印流:PrintStream / PrintWriter
PrintStream接口特性:
- 扩展自
FilterOutputStream - 不会抛出IOException异常
- 可设置自动刷新功能
主要方法:
println(): 打印数据并添加换行符print(): 打印数据不添加换行符printf(): 格式化输出checkError(): 检查是否发生错误
PrintWriter接口特性:
- 基于字符流,支持国际化字符
- 提供与PrintStream相同的打印方法
- 可指定字符编码
示例:
java
PrintWriter writer = new PrintWriter(System.out, true);
writer.println("这是一条日志信息");🔹 对象流:ObjectInputStream / ObjectOutputStream
接口特性:
- 实现
ObjectInput/ObjectOutput接口 - 支持对象序列化和反序列化
- 要求对象类实现
Serializable接口
ObjectOutputStream主要方法:
writeObject(Object obj): 序列化对象writeStreamHeader(): 写入流头部信息- 其他继承自DataOutputStream的写入方法
ObjectInputStream主要方法:
Object readObject(): 反序列化对象readStreamHeader(): 读取流头部信息- 其他继承自DataInputStream的读取方法
示例:
java
class Student implements Serializable {
private static final long serialVersionUID = 1L;
String name;
int age;
}
// 序列化
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("student.ser"))) {
oos.writeObject(new Student("张三", 20));
}
// 反序列化
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("student.ser"))) {
Student s = (Student) ois.readObject();
System.out.println(s.name + ", " + s.age);
}🔹 字节数组流:ByteArrayInputStream / ByteArrayOutputStream
ByteArrayInputStream接口特性:
- 从内存字节数组读取数据的输入流
- 不需要关闭,没有底层资源
主要方法:
- 继承自InputStream的所有方法
available(): 返回可读取的字节数mark(int)和reset(): 支持标记和重置
ByteArrayOutputStream接口特性:
- 输出数据到内存字节数组的输出流
- 可动态增长的字节缓冲区
主要方法:
- 继承自OutputStream的所有方法
toByteArray(): 获取内部字节数组副本toString(): 将内容转换为字符串writeTo(OutputStream): 写入到其他输出流
示例:对象深复制(通过序列化)
java
public static <T extends Serializable> T deepCopy(T object) throws IOException, ClassNotFoundException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(object);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
return (T) ois.readObject();
}四、字符流体系
🔹 抽象类:Reader / Writer
Reader接口与主要方法:
int read(): 读取单个字符int read(char[] cbuf): 读取多个字符到数组int read(char[] cbuf, int off, int len): 读取指定长度到数组指定位置void close(): 关闭流并释放资源boolean ready(): 检查流是否准备好被读取
Writer接口与主要方法:
void write(int c): 写入单个字符void write(char[] cbuf): 写入字符数组void write(char[] cbuf, int off, int len): 写入部分字符数组void write(String str): 写入字符串void write(String str, int off, int len): 写入部分字符串void flush(): 刷新缓冲区void close(): 关闭流并释放资源
🔹 转换流:InputStreamReader / OutputStreamWriter
接口特性:
- 字节流和字符流之间的桥梁
- 可指定字符编码,支持国际化
InputStreamReader主要方法:
- 继承自Reader的所有方法
String getEncoding(): 获取使用的编码
OutputStreamWriter主要方法:
- 继承自Writer的所有方法
String getEncoding(): 获取使用的编码
示例:指定 UTF-8 编码写入中文
java
try (OutputStreamWriter writer = new OutputStreamWriter(
new FileOutputStream("utf8.txt"), "UTF-8")) {
writer.write("你好,世界!");
}🔹 文件字符流:FileReader / FileWriter
接口特性:
FileReader是InputStreamReader的子类FileWriter是OutputStreamWriter的子类- 默认使用系统平台的字符编码
主要方法:
- 继承自Reader/Writer的所有方法
- 没有添加新方法,主要简化构造函数
示例:
java
try (FileReader reader = new FileReader("hello.txt")) {
int ch;
while ((ch = reader.read()) != -1) {
System.out.print((char) ch);
}
}🔹 缓冲字符流:BufferedReader / BufferedWriter
接口特性:
- 为字符流提供缓冲功能
- 支持按行读写操作
BufferedReader主要方法:
- 继承自Reader的所有方法
String readLine(): 读取一行文本,不包含换行符
BufferedWriter主要方法:
- 继承自Writer的所有方法
void newLine(): 写入一个平台相关的换行符
示例:逐行读取文件
java
try (BufferedReader br = new BufferedReader(new FileReader("data.txt"))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
}🔹 打印流:PrintWriter
接口特性:
- 提供格式化输出功能
- 不会抛出IOException
- 可自动刷新
主要方法:
- 继承自Writer的所有方法
println(): 打印并换行print(): 打印不换行printf(): 格式化输出format(): 格式化输出checkError(): 检查错误状态
示例:
java
PrintWriter writer = new PrintWriter(System.out, true);
writer.printf("姓名: %s, 年龄: %d%n", "李四", 25);五、随机访问文件:RandomAccessFile
接口特性:
- 实现了
DataInput和DataOutput接口 - 既不是InputStream也不是OutputStream的子类
- 支持随机读写文件中的任意位置
主要方法:
long getFilePointer(): 获取当前文件指针位置void seek(long pos): 设置文件指针位置long length(): 获取文件长度int skipBytes(int n): 跳过n个字节- 继承自DataInput/DataOutput的所有读写方法
构造函数模式:
"r": 只读模式"rw": 读写模式"rws": 读写模式,同步文件内容和元数据更新"rwd": 读写模式,同步文件内容更新
示例:
java
try (RandomAccessFile raf = new RandomAccessFile("random.dat", "rw")) {
raf.writeInt(100); // 写入整数
raf.seek(0); // 移动指针到开头
System.out.println(raf.readInt()); // 读取整数
}六、操作文件的工具类
🔹 Path 接口 和 Paths 类
Path接口主要方法:
Path getFileName(): 获取文件名Path getParent(): 获取父路径Path resolve(Path/String): 解析路径Path relativize(Path): 获取相对路径Path normalize(): 规范化路径File toFile(): 转换为File对象boolean startsWith(Path/String): 判断是否以指定路径开始boolean endsWith(Path/String): 判断是否以指定路径结束
Paths类主要方法:
static Path get(String first, String... more): 获取路径实例static Path get(URI uri): 通过URI获取路径
示例:
java
Path path = Paths.get("data", "input.txt");
System.out.println(path.toString()); // Windows: data\input.txt🔹 Files 类
主要静态方法:
- 文件操作:
createFile(),delete(),copy(),move() - 目录操作:
createDirectory(),createDirectories() - 读取内容:
readAllBytes(),readAllLines(),lines() - 写入内容:
write(),writeString() - 属性读取:
size(),getLastModifiedTime(),isDirectory(),isRegularFile() - 遍历目录:
list(),walk(),find()
示例:
java
// 创建目录
Files.createDirectories(Paths.get("temp", "logs"));
// 读取文件内容
List<String> lines = Files.readAllLines(Paths.get("data.txt"));
lines.forEach(System.out::println);七、流的分类汇总表
| 类型 | 节点流 | 处理流 |
|---|---|---|
| 字节流 | FileInputStream / FileOutputStreamByteArrayInputStream / ByteArrayOutputStream | BufferedInputStream / BufferedOutputStreamDataInputStream / DataOutputStreamObjectInputStream / ObjectOutputStream |
| 字符流 | FileReader / FileWriterCharArrayReader / CharArrayWriter | InputStreamReader / OutputStreamWriterBufferedReader / BufferedWriterPrintWriter |
八、流的设计模式:装饰器模式(Decorator Pattern)
FilterInputStream/FilterOutputStream是所有处理流的基类- 通过组合方式动态扩展流功能,避免类爆炸
- 示例结构:
InputStream
↳ FileInputStream ← 节点流(真实源)
↳ FilterInputStream ← 抽象装饰类
↳ BufferedInputStream ← 具体装饰类1(加缓冲)
↳ DataInputStream ← 具体装饰类2(读写基本类型)
↳ ObjectInputStream ← 具体装饰类3(支持对象序列化)九、总结建议
| 场景 | 推荐使用的流 |
|---|---|
| 顺序读写二进制文件 | FileInputStream / FileOutputStream |
| 顺序读写文本文件 | FileReader / FileWriter 或 InputStreamReader / OutputStreamWriter |
| 读写基本数据类型 | DataInputStream / DataOutputStream |
| 读写对象 | ObjectInputStream / ObjectOutputStream |
| 格式化输出 | PrintWriter |
| 随机访问文件 | RandomAccessFile |
| 文件管理 | Path / Paths / Files |
十、思维导图结构(建议整理为笔记大纲)
你可以将以下结构作为整理笔记的大纲:
第12章 Java输入输出流
├── I/O基本概念
├── 流的分类
│ ├── 按方向:输入流 / 输出流
│ ├── 按单位:字节流 / 字符流
│ └── 按功能:节点流 / 处理流
├── 字节流体系
│ ├── InputStream / OutputStream
│ ├── FileInputStream / FileOutputStream
│ ├── BufferedInputStream / BufferedOutputStream
│ ├── DataInputStream / DataOutputStream
│ ├── ObjectInputStream / ObjectOutputStream
│ └── ByteArrayInputStream / ByteArrayOutputStream
├── 字符流体系
│ ├── Reader / Writer
│ ├── InputStreamReader / OutputStreamWriter
│ ├── FileReader / FileWriter
│ ├── BufferedReader / BufferedWriter
│ └── PrintWriter
├── RandomAccessFile
└── 文件操作工具类
├── Path / Paths
└── Files