思想重于代码
一、IO 流概述
1. 什么是 IO
I:Input 输入(读),把文件 / 网络 数据读到程序内存 O:Output 输出(写),把程序内存的数据写到文件 / 网络
参照物:Java 程序内存
2. IO 流分类
按数据单位分(最核心)
- 字节流 :操作字节 byte,万能流。可以读写一切文件(文本、图片、视频、音频) 父类:
InputStream(字节输入)、OutputStream(字节输出) - 字符流 :操作字符 char,只能读写纯文本文件 (txt、java),底层还是字节 + 自动按字符集解码 父类:
Reader(字符输入)、Writer(字符输出)
按流向
- 输入流:文件 → 程序
- 输出流:程序 → 文件
按角色
- 节点流(原始流):直接对接文件
- 处理流(包装流):包裹其他流,增强功能(缓冲流、转换流)
记忆口诀:字节万能,字符只处理文本;读是输入,写是输出。
3. IO 流体系总表
| 分类 | 输入流 (读) | 输出流 (写) |
|---|---|---|
| 字节流 | InputStream | OutputStream |
| 节点流 | FileInputStream | FileOutputStream |
| 字符流 | Reader | Writer |
| 节点流 | FileReader | FileWriter |
| 转换流 | InputStreamReader(字节→字符) | OutputStreamWriter(字符→字节) |
| 缓冲流 | BufferedReader | BufferedWriter |
| 缓冲字节流 | BufferedInputStream | BufferedOutputStream |
二、字节流(万能流)
FileOutputStream 文件字节输出流(写文件)
作用:写出字节 / 字节数组到文件
注意:新建流对象,默认覆盖原有文件内容 ;构造第二个参数写
true代表追加续写,不覆盖。
java
// false:覆盖(默认),true:追加
FileOutputStream fos = new FileOutputStream("a.txt",true);
fos.write(97); // 写单个字节 a
fos.write("你好".getBytes(StandardCharsets.UTF_8)); //写字节数组
fos.close(); // 释放资源!必须写
FileInputStream 文件字节输入流(读文件)
java
FileInputStream fis = new FileInputStream("a.txt");
byte[] buf = new byte[1024]; // 缓冲区数组
int len;
// len代表本次读到的字节数量,读到末尾返回-1
while((len = fis.read(buf)) != -1){
System.out.print(new String(buf,0,len));
}
fis.close();
重点:
read()返回 int,读到文件末尾返回 -1。
✅ 使用场景:图片、视频、拷贝文件(文件拷贝首选字节流) 文件拷贝模板:读一个字节数组,写出一个字节数组。
三、字符流(只处理纯文本)
FileReader / FileWriter
底层:字节流 + 系统默认字符集解码。 ⚠️ 缺点:不能手动指定字符集!Windows 默认 GBK,极易乱码。
开发不推荐 FileReader/FileWriter,仅做学习。
java
FileReader fr = new FileReader("a.txt");
int ch;
while((ch = fr.read()) != -1){
System.out.print((char)ch);
}
fr.close();
四、转换流(重点!解决字符集乱码)
作用:字节流 ↔ 字符流,可以手动指定字符集
InputStreamReader:字节输入 → 字符输入(解码)OutputStreamWriter:字符输出 → 字节输出(编码)
java
// 读取GBK编码的文本文件
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"), StandardCharsets.GBK);
// 写出UTF-8文本
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("b.txt"), StandardCharsets.UTF_8);
面试考点:转换流是字符流和字节流之间的桥梁。
五、缓冲流(处理流,提升读写速度)
底层自带缓冲区数组,减少磁盘 IO 次数,速度远高于普通节点流。
字节缓冲流
BufferedInputStream / BufferedOutputStream
只是加速,功能和普通字节流一样,万能,可拷贝图片视频。
字符缓冲流
BufferedReader / BufferedWriter 特有方法:
BufferedReader.readLine():读取一行字符串,读到末尾返回 nullBufferedWriter.newLine():自动换行,跨平台兼容(Windows\r\n Linux\n)
java
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
String line;
while((line = br.readLine()) != null){
System.out.println(line);
}
br.close();
⚠️ 字符缓冲流只能读文本!
六、资源释放 try-catch-finally /try-with-resources
1. finally 写法(老写法)
finally 代码块一定会执行,用来关闭流,防止资源泄漏。
java
FileInputStream fis = null;
try{
fis = new FileInputStream("a.txt");
//读写操作
}catch(IOException e){
e.printStackTrace();
}finally {
if(fis != null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
2. try-with-resources【JDK7 + 推荐,重点】
自动实现资源关闭,不用手动写 close () 实现 AutoCloseable 接口的流都可以放 try () 括号内。
java
try(FileInputStream fis = new FileInputStream("a.txt");
FileOutputStream fos = new FileOutputStream("b.txt")){
//拷贝代码
}catch (IOException e){
e.printStackTrace();
}
七、IO 流面试核心考点总结
- 字节流可以读写所有文件;字符流只能纯文本。
- FileReader/FileWriter 无法指定编码,容易乱码;需要指定编码用转换流。
- 缓冲流目的:提高读写性能,减少磁盘 IO。BufferedReader 特有 readLine ()。
- 流使用完必须关闭释放资源,推荐 try-with-resources 自动关闭。
- 文件拷贝标准方案:字节缓冲流。
- read () 返回 - 1、readLine () 返回 null,代表读到文件末尾。
八、常见易错点
❌ 字符流读取图片视频:会损坏文件! ❌ 字节流读取文本:需要自己转 String,手动处理字符集。 ❌ 忘记关闭流:操作系统文件资源不释放,占用句柄。
java
io.write("\r\n");//输出文本换行
io.flush();//压出
io.close();//压出后关闭
//拓展打印流