Java中有关流的知识
一、流的核心概念
- 什么是IO流
IO = Input(输入) / Output(输出),流是数据传输的通道,用来读写文件、网络、内存等数据,本质就是字节/字符的有序序列。
- 输入流:读数据(程序←外部)
- 输出流:写数据(程序→外部)
- 两大分类(顶层父类)
(1)字节流:操作字节 byte,万能流(图片、视频、文档、所有文件)
父类抽象类:
InputStream:所有字节输入流父类OutputStream:所有字节输出流父类
(2)字符流:操作字符 char,只处理文本文件(.txt/.java/.md)
父类抽象类:
Reader:所有字符输入流父类Writer:所有字符输出流父类
区分口诀:后缀是Stream=字节;Reader/Writer=字符
二、字节流详解
1. 文件字节流(基础)
FileInputStream 文件字节输入流(读文件)
构造方法:
// 传入文件路径
FileInputStream fis = new FileInputStream("a.txt");
// 传入File对象
File file = new File("a.txt");
FileInputStream fis = new FileInputStream(file);
核心读取方法:
int read():读取1个字节,返回字节值;读到文件末尾返回-1int read(byte[] b):批量读取到字节数组,返回读取长度,无数据返回-1close():关闭流,释放资源(必须执行)
示例读取文件:
import java.io.FileInputStream;
import java.io.IOException;
public class Test {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("test.txt");
byte[] buf = new byte[1024]; // 缓冲区数组
int len;
// 循环读取
while ((len = fis.read(buf)) != -1) {
// 从数组0开始,打印len长度数据
System.out.print(new String(buf, 0, len));
}
fis.close(); // 关闭流
}
}
FileOutputStream 文件字节输出流(写文件)
构造:
// 覆盖写入:每次创建清空原有内容
FileOutputStream fos = new FileOutputStream("b.txt");
// 追加写入:第二个参数true,数据追加到文件末尾
FileOutputStream fos = new FileOutputStream("b.txt", true);
写入方法:
write(int b):写入单个字节write(byte[] b):写入整个字节数组write(byte[] b,int off,int len):写入数组指定区间flush():刷新缓冲区(字节流缓冲区很小,可省略;字符流必须)close():关闭流(关闭前自动flush)
2. 缓冲字节流(提速,包装流)
底层自带缓冲区,减少磁盘IO,读写速度远高于普通文件流
BufferedInputStream缓冲字节输入BufferedOutputStream缓冲字节输出
用法:包装原始文件流
FileInputStream fis = new FileInputStream("1.jpg");
BufferedInputStream bis = new BufferedInputStream(fis);
FileOutputStream fos = new FileOutputStream("copy.jpg");
BufferedOutputStream bos = new BufferedOutputStream(fos);
关闭规则:只关外层缓冲流,内层流会自动关闭。
3. 对象字节流(序列化)
实现对象读写,把对象存入文件/网络传输
ObjectInputStream:读对象(反序列化)ObjectOutputStream:写对象(序列化)
要求:实体类必须实现Serializable标记接口
class User implements Serializable {
String name;
int age;
}
核心方法:
writeObject(Object obj)写对象readObject()读取对象,返回Object需要强转
三、字符流详解(只处理文本)
1. 文件字符流
FileReader 字符输入流
read() 读取单个字符,read(char[] cbuf) 批量读取字符数组
FileWriter 字符输出流
特有:自带字符缓冲区,写完必须flush()/close() 数据才会落地到文件
FileWriter fw = new FileWriter("c.txt");
fw.write("你好Java");
fw.flush(); // 刷新缓冲区,数据写入磁盘
fw.close();
2. 缓冲字符流(常用,带一行读写)
BufferedReader:字符缓冲输入
独有方法:String readLine()读取一整行字符串,无内容返回nullBufferedWriter:字符缓冲输出
独有方法:newLine()换行(跨平台兼容)
示例按行读写文本:
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("copy.txt"));
String line;
while ((line = br.readLine()) != null) {
bw.write(line);
bw.newLine(); // 换行
}
bw.flush();
bw.close();
br.close();
3. 转换流(字节 ↔ 字符桥梁,处理编码)
解决中文乱码核心类,可指定读写编码(UTF-8/GBK)
InputStreamReader:字节输入流转字符输入流OutputStreamWriter:字符输出流转字节输出流
指定UTF-8读取文件:
FileInputStream fis = new FileInputStream("utf.txt");
// 字节流转字符流,指定编码
InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
BufferedReader br = new BufferedReader(isr);
四、IO流异常处理(标准写法 try-catch-finally / try-with-resources)
1. 传统finally(JDK7前)
finally中关闭流,防止资源泄漏
FileReader fr = null;
try {
fr = new FileReader("a.txt");
// 读写操作
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fr != null) {
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
2. try-with-resources(JDK7推荐,最简)
实现 AutoCloseable 接口的流,代码执行完毕自动关闭,无需手动close
// 流定义在try()括号内,自动释放
try (BufferedReader br = new BufferedReader(new FileReader("a.txt"))) {
String s = br.readLine();
System.out.println(s);
} catch (IOException e) {
e.printStackTrace();
}
五、标准流(控制台输入输出)
属于字节流,系统默认流,无需手动关闭
System.out:PrintStream 控制台输出System.in:InputStream 控制台键盘输入System.err:错误输出流
常用键盘读取包装:
Scanner sc = new Scanner(System.in);
// 或字符缓冲读取
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String input = br.readLine();
六、打印流 PrintStream / PrintWriter
只输出,不抛IO异常,自动刷新,开发常用
- PrintStream:字节打印流(System.out本质就是它)
- PrintWriter:字符打印流,可包装文件、流
优势:print()/println() 支持任意数据类型自动转字符串
七、NIO(补充:JDK1.4非阻塞IO,区别传统BIO)
我们上面讲的全部是 BIO 同步阻塞IO(一个连接一个线程,读写阻塞)
NIO三大核心:Channel通道、Buffer缓冲区、Selector选择器,适合高并发网络编程。
八、高频面试区分点
- 字节流和字符流使用场景
- 字节流:图片、视频、音频、压缩包、任意文件复制
- 字符流:仅纯文本文件读写
- 缓冲流作用:内置缓冲区,减少磁盘IO交互,大幅提升读写性能
- flush()作用:清空内存缓冲区,把数据写入磁盘;字符流必须刷新
- 序列化条件:类实现Serializable接口,静态变量不会序列化
- 转换流作用:设置文件编码,解决中文乱码
- 关闭流顺序:先关外层包装流,外层关闭自动关闭内层原始流
九、文件复制通用模板(缓冲字节流,万能复制)
import java.io.*;
public class CopyFile {
public static void main(String[] args) {
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("source.jpg"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("target.jpg"))) {
byte[] buf = new byte[1024 * 8]; // 8KB缓冲区
int len;
while ((len = bis.read(buf)) != -1) {
bos.write(buf, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
浙公网安备 33010602011771号