qaq
IO流分类
字节流
- 可以操作所有类型的文件
- 读取文件的时候不要有中文
- 每次只能操作一个字节(整数不能超过一个字节)
子类
- InputStream
- OutputStream
字符流
- 只能操作纯文本文件
子类
- Reader
- Writer
字节流
字节输出流
FileOutputStream(File filename, boolean append)FileOutputStream(String filepath)
字节输入流
1 | FileInputStream fis = new FileInputStream(""); |
文件拷贝
小文件
1 | FileInputStream fis = new FileInputStream(""); |
文件大的时候一次次read()太慢
1 | FileInputStream fis = new FileInputStream(""); |
字符流
- 字符流 = 字节流 + 字符集
特点
- 输入流:一次读一个字节,遇到中文时,一次读多个字节
- 输出流:底层把数据按照指定的编码方式进行编码,变成字节再写到文件中
使用场景
- 操作纯文本文件
FileReader
public int read():读取数据,到末尾返回 -1public int read(char[] buffer):读取多个数据,到末尾返回 -1- 细节:按字节进行读取,遇到中文,一次读多个字节,读取后解码,返回一个十进制整数,代表在字符集上的数字
- 字符流的底层也是字节流
1 | FileReader fr = new FileReader(""); |
1 | FileReader fr = new FileReader(""); |
FileWriter
1 | FileWriter fw = new FileWriter(""); |
1 | FileWriter fw = new FileWriter(""); |
字符流底层原理
- 创建字符输入流对象
- 关联文件,并创建缓冲区(长度为8192的字节数组)(字节流无缓冲区)
- 读取数据
- 判断缓冲区中是否有数据
- 缓冲区无数据:从文件中获取数据,装入缓冲区,尽可能装满
- 缓冲区有数据:从缓冲区读取
- 空参read:一次读取一个字节,遇到中文一次读多个字节,把字节解码转成十进制返回
- 有参read:读取字节、解码、强转三步合并,强转后的字符放到数组中
- 判断缓冲区中是否有数据
- 输出数据
- 在内存中创建一个8192的缓冲区,每一次write都会把内容编码写进缓冲区里,出现下面的情况时,会把缓冲区内容写入文件
- 缓冲区满
- 刷新(
flush()) - 关流(
close())
- 在内存中创建一个8192的缓冲区,每一次write都会把内容编码写进缓冲区里,出现下面的情况时,会把缓冲区内容写入文件
缓冲流
加了缓冲区的基本流
字节缓冲流
public BufferedInputStream(InputStream is)public BufferedOutputStream(OutputStream os)
字符缓冲流
因为字符基本流已经有缓冲区了,所以效率提高不明显
BufferedReaderBufferedWriter
主要体现在两个比较好用的方法
- 输入流:
public String readLine():读取一行数据,如果没数据了,返回null。但是不会读取回车换行 - 输出流:
public void newLine():跨平台的换行
转换流
是字符流和字节流之间的桥梁
数据源 -> 字节流 -> 转换流 -> 内存 -> 转换流 -> 字节流 ->目的文件
InputStreamReaderOutputStreamWriter
1 | InputStreamReader isr = new InputStreamReader(new FileInputStream(""), "GBK"); |
1 | OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(""), "GBK"); |
JDK11后把FileInputStream和FileOutputStream的构造方法加入了字符编码
1 | //将本地文件中的GBK文件,转成UTF-8 |
练习
1 | //用字节流读文件中数据,一次读一行,不能出现乱码 |
序列化流
- 是字节流的一种
- 可以把Java中的对象写到本地文件中
- 是高级流
构造方法
public ObjectOutputStream(OutputStream out):基本流包装成高级流public final void writeObject(Object obj):把对象序列化写出
输出
1 | Student stu = new Student("a", 18); |
注意:要序列化的Javabean类需要实现Serializable接口,Serializable接口是个标记接口
输入
1 | ObjectInputStream ois = new ObjectInputStream(new FileInputStream("")); |
版本号
当一个对象实现了Serializable接口之后,每一次修改这个Javabean类都会生成新的版本号,而每次序列化会把版本号序列化进去,使得在反序列化时可能会出现序列化的对象和当前Javabean类版本号不一致的问题
可以固定版本号
1
2
3public class Student implements Serializable {
private static final long serialVersionUID = 1L;// 唯一格式 建议自动生成
}
transient关键字
- 瞬态关键字
- 被此关键字修饰的变量不会被序列化到本地文件中
1 | private transient String address; |
打印流
只有输出流
字节打印流 和 字符打印流
不能操作数据源,只能操作目的地
PrintStream
PrintWriter
字节打印流
字节流底层没缓冲区,自动刷新开不开没区别
构造
public PrintStream(OutputStream/File/String):关联字节输出流/文件/文件路径public PrintStream(String fileName, Charset charset):指定字符编码public PrintStream(OutputStream out, boolean autoFlush):自动刷新public PrintStream(OutputStream out, boolean autoFlush, String encoding):指定字符编码
方法
public void write(int b):常规方法,和之前一样public void println(Xxx xx):特有方法,打印任意数据,自动刷新、换行public void print(Xxx xx):特有方法,打印任意数据,不换行public void printf(String format, Object...):特有方法,带有占位符的打印语句,不换行
1 | PrintStream ps = new PrintStream(new FileOutputStream(""), true, Charset.forName("GBK")); |
字符打印流
字符流底层有缓冲区,要自动刷新需要手动开启
构造
public PrintWriter(Writer/File/String):关联字节输出流/文件/路径public PrintWriter(String fileName, Charset charset):指定字符编码public PrintWriter(Write w, boolean autoFlush):自动刷新public PrintWriter(OutputStream out, boolean autoFlush, Charset charset):指定字符编码且自动刷新
方法
和字节打印流一样
1 | PrintWriter pw = new PrintWriter(new FileWriter(""), true); |
用处
System.out是一个静态打印流对象,虚拟机启动的时候,由JVM赋值,默认指向控制台
压缩流
- 只能识别.zip文件
- 压缩包里每一个文件在Java中是一个ZipEntry对象
- 解压本质:把每一个ZipEntry对象按照层级拷贝到本地另一个文件夹中
解压缩流
ZipInputStream
未完待续