IO流:存储和读取数据的解决方案,用于读写文件中的数据。
IO流使用原则:什么时候使用什么时候创建,什么时候不用,什么时候关闭。
IO流的分类
1)按照流向分:输出流(从程序写到文件中),输入流(从文件写到程序中)。
2)按照操作文件的类型:字节流(可以操作所有类型的文件),字符流(只能操作纯文本文件)
1.IO流体系的基本流
下面四个都是抽象类,不能直接创建对象。

1.1字节流
1)FileOutputStream
FileOutputStream:操作本地文件的字节输出流,可以把程序中的数据写到本地文件中。
FileOutputStream写数据的三种方式:

FileOutputStream进行换行操作:Windows:\r\n Linux:\n Mac:\r
FileOutputStream进行续写操作:如果想要续写打开续写开关即可,创建对象的第二个参数就是续写开关,默认为false,表示关闭续写,此时创建文件会清空文件,手动传递false,表示打开续写,此时就不会再清空文件,而是接在后面写。
步骤:
1>创建字节输出流对象
参数是字符串表示的路径或者是File对象都可以;如果文件不存在会创建一个新的文件,但是要保证父级路径是存在的;如果文件已经存在,则会清空文件
2>写数据
write方法的参数是整数,但是实际写到本地文件中的是整数在ASCII上对应的字符
3>释放资源
每次使用完之后都要释放资源,释放相当于解除资源的占用。
2)FileInputStream
FileInputStream:操作本地文件的字节输入流,可以把本地文件中的数据读取到程序中。
FileInputStream写数据的两种方式:

一次读取一个字节数组的数据,每次读取会尽可能把数组装满。数组大小尽可能为1024的整数倍
步骤:
1>创建字节输入流对象
如果文件不存在,直接报错
2>读数据
一次读取一个字节,读出来的是ASCII上对应的数字,读到文件末尾了,read方法返回-1
3>释放资源

1.2字符集
1)ASCII字符集
2)GBK
存储汉字规则:1>汉字使用两个字节进行存储 2>高位字节二进制一定是以1开头,转成十进制之后是一个负数 3>GBK汉字编码规则不需要变动
核心1:GBK中,一个英文字母一个字节,二进制第一位是0
核心2:GBK中,一个中文汉字两个字节,二进制第一位是1
3)Unicode
UTF-8编码规则:用1-4个字节保存
ASCII采用一个字节二进制的第一位是0;简体中文三个汉字

1.3字符流
字符流的底层是字节流(字符流=字节流+字符集)
特点:
输入流:一次读一个字节,遇到中文时,一次读多个字节
输出流:底层会把数据按照指定的编码方式进行编码,变成字节再写道文件中
使用场景:对于纯文本文件进行读写操作
1)FileReader
步骤:
1>创建字符输入流对象

如果文档不存在,就会直接报错
2>读取数据

按字节进行读取,遇到中文,一次读多个字节,读取后解码成十进制,返回一个整数;读到文件末尾时,read方法返回-1
3>释放资源

2)FileWriter
构造方法:


没有打开续写开关就会清空文件,使用FileReader读取文件时,先装满8192个字节数组,所以先读取缓冲区的字节数组内容,即使使用的FileWriter/FileOutputStream清空了内容,使用FileReader读取时还是可以读取缓冲区已经存在的数据,剩下的未装进缓冲区的数据无法读取。


字节流和字符流的使用场景
字节流:拷贝任意类型的文件
字符流:读取纯文本文件中的数据;往纯文本文件中写入数据
2.IO流体系的高级流
2.1缓冲流

1)字节缓冲流
原理:底层自带了长度为8192的缓冲区,显著提高字节流的读写性能。对于字符流来说不明显
构造方法:

字节缓冲流提高效率的原理:

不断从输入的缓冲区运输到输出的缓冲区里面,这里的过程都是在内存里面进行的,内存运行的速度非常快,几乎忽略不计,节省的时间是读写时和硬盘交流的时间。
2)字符缓冲流
构造方法:


一次读一整行,遇到回车换行结束,但是不会把回车换行读到内存中。

2.2转换流
转换流是字符流和字节流之前的桥梁。
作用:1)指定字符集读写 2)字节流想要使用字符流中的方法
字符转换输入流:InputStreamReader
字符转换输出流:OutputSreamWriter
2.3序列化流
序列化流:也叫对象操作输出流,可以把Java中的对象写到本地文件中
构造方法:

成员方法:

序列化流使用输出流将对象保存到文件时会出现NotSerializationException异常,需要让对象的JavaBean类实现Serializable接口
Serializable接口里面是没有抽象方法的,是标记型接口,一旦实现这个接口,那么就表示当前的类可以被序列化
反序列化流:也叫对象操作输入流,可以把序列化到本地文件中的对象,读取到程序中来。
构造方法:

成员方法:

java
public static void main(String[] args) throws IOException, ClassNotFoundException {
//创建对象
Student stu = new Student("zhangsan",23);
//创建序列化流的对象/操作对象输出流
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("src/heimaPractice/FileAndIO/a.txt"));
//写出数据
oos.writeObject(stu);
oos.close();
//创建反序列化流对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("src/heimaPractice/FileAndIO/a.txt"));
//读取数据
Student o = (Student)ois.readObject();
//打印对象
System.out.println(o);
ois.close();
}
//实现接口
class Student implements Serializable{}
2.4打印流
打印流不能读只能写,分为字节打印流和字符打印流。
分类:打印流一般是指PrintStream,PrintWriter
特点1:打印流纸草纸文件目的地,不操作数据源
特点2:特有的写出方法可以实现,数据原样写出
特点3:特有的写出方法,可以实现自动刷新,自动换行。
1)字节打印流:
构造方法:

字节流底层没有缓冲区,开不开自动刷新都一样
成员方法:

2)字符打印流
字符打印流底层有缓冲区,想要自动刷新需要开启
构造方法:

成员方法:

2.5压缩流/解压缩流
解压缩流:ZipInputStream
解压的本质就是把每一个ZipEntry按照层级拷贝到本地另一个文件夹当中
java
public static void unzip(String src, String dest) throws IOException {
//创建解压缩六来读取压缩包中的数据
ZipInputStream zip = new ZipInputStream(new FileInputStream(src));
ZipEntry entry;
while((entry=zip.getNextEntry())!=null){
System.out.println(entry.getName());
if(entry.isDirectory()){
//如果是文件夹,在目的地dest处创建一个同样的文件夹
File file = new File(dest,entry.toString());
file.mkdir();
} else {
//如果是文件,需要读取到压缩包中的文件,并把他存放到目的地dest中(需要按照层级目录进行存放)
FileOutputStream fos = new FileOutputStream(new File(dest,entry.getName()));
int b;
while((b=zip.read())!=-1){
fos.write(b);
}
fos.close();
//表示压缩包里面的一个文件处理完毕
zip.closeEntry();;
}
}
}
压缩流:ZipOutputStream
压缩本质:把每一个文件/文件夹堪称ZipEntry对象放到压缩包中
java
/**
* 压缩--单个文件
* @param src
* @param dest
*/
public static void tozip(File src, File dest) throws IOException {
//创建压缩流关联压缩包
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(new File(dest,src.getName().split("\\.")[0]+".zip")));
//创建ZipEntry对象,表示压缩包里面的每一个文件和文件夹
ZipEntry entry = new ZipEntry(src.getName());
//把ZipEntry对象放到压缩包当中
zos.putNextEntry(entry);
//把src文件中的数据写到压缩包当中
FileInputStream fis = new FileInputStream(src);
int b;
while((b=fis.read())!=-1){
zos.write(b);
}
fis.close();
zos.closeEntry();
zos.close();
}
/**
* 压缩--多个文件
* @param src
* @param dest
*/
public static void tozip2(File src, File dest) throws IOException {
//创建压缩流关联压缩包
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(new File(dest,src.getName().split("\\.")[0]+".zip")));
//获取src的每一个文件,变成zipEntry对象,放入到压缩包当中
toZip(src,zos,src.getName());
zos.close();
}
/**
* 递归压缩--获取src里面的每一个文件,变成ZipEntry对象,再放入压缩包当中
* @param src --数据源
* @param zos --压缩流
* @param name --压缩包内部路径
*/
public static void toZip(File src,ZipOutputStream zos,String name) throws IOException {
File[] files = src.listFiles();
for (File file : files) {
if(file.isFile()){
//变成ZipEntry对象放入压缩包--这个路径应该是aaa\\a.txt
ZipEntry entry = new ZipEntry(name+"\\"+file.getName());
zos.putNextEntry(entry);
//读取文件中的数据写到压缩包
FileInputStream fis = new FileInputStream(file);
int b;
while((b=fis.read())!=-1){
zos.write(b);
}
fis.close();
zos.closeEntry();
} else {
toZip(file,zos,name+"\\"+file.getName());
}
}
}
2.6Commons-io
Commons-io是apache开源基金组织提高的一组有关IO操作的开源工具包
作用:提高IO流的开发效率


1.7Hutool工具包

拓展:配置文件
好处1:可以把软件的设置永久化存储
好处2:需要修改参数时,不需要改动代码,直接修改配置文件即可
properties是一个双列集合,拥有Map集合的所有特点
重点:有一些特有的方法,可以把集合中的数据,按照键值对的形式写到配置文件当中。也可以把配置文件中的数据读取到集合当中。
