IO流
存储和读取数据的解决方案
I:input O:output
IO流的作用
用于读写(本地文件,网络)
IO流的分类
纯文本文件:用Windows系统自带的记事本打开并且能读懂的文件
IO流的体系
字节流
FileOutputStream
操作本地文件的字节输出流,可以把程序中的数据写到本地文件中
书写步骤:
①创建字节输出流对象
- 参数是字符串表示的路径或者File对象都是可以的
- 如果文件不存在会创建一个新的文件,但是要保证父级路径是存在的
- 如果文件已经存在,则会清空文件
②写数据
- writer方法的参数是整数,但是实际上写到本地文件中的是整数在ASCII上对应的字符
③释放资源
- 每次使用完流之后都要释放资源
FileOutputStream
操作本地文件的字节输入流,可以把本地文件中的数据读取到程序中来。
书写步骤:
①创建字节输入流对象
- 如果文件不存在,就直接报错。
②写数据
- 一次读一个字节,读出来的是数据在ASCII上对应的数字。
- 读到文件末尾了,read方法返回-1。
③释放资源
- 每次使用完流之后都要释放资源。
IO流中不同JDK版本捕获异常的方式
字符流
字符集
ASCII&&GBK
总结
1.在计算机中,任意数据都是以二进制的形式来存储的
2.在计算机中最小的存储单元是一个字节
3.ASCII字符集中,一个英文占一个字节
4.简体中文版Windows,默认使用GBK字符集
5.GBK字符集完全兼容ASCII字符集
- 一个英文占一个字节,二进制第一位是0
- 一个中文占两个字节,二进制高位字节的第一位是1
Unicode
总结
1.Unicode字符集的UTF-8编码格式
-
一个英文占一个字节,二进制第一位是0,转成十进制是正数
-
一个中文占三个字节,二进制第一位是1,第一个字节转成十进制是负数。
为什么会有乱码
1.读取数据是为读完整个汉字
2.编码和解码时的方式不统一
解决方法
1.不要用字节流读取文本文件
2.编码解码时使用同一个码表,同一个编码方式
FileReader
书写步骤
①创建字符输入流对象
②读取数据
细节1:按字节进行读取,遇到中文,一次读取多个字节,读取后解码,返回一个整数。
细节2:读到文件末尾了,read方法返回-1
③释放资源
FileWriter
构造方法
成员方法
书写细节
①创建字符输出流对象
细节1:参数是字符串表示的路径或者File对象都是可以的
细节2:如果文件不存在会创建一个新的文件,但是要保证父级路径是存在的
细节3:如果文件已经存在,则会清空文件,如果不想清空可以打开续写开关
②写数据
细节:如果Writer方法的参数是整数,但是实际上写到本地文件中的是整数在字符集上对应的字符
③释放对象
细节:每次使用完流之后都要释放资源
字符输入流原理解析
字符输出流原理解析
flush和close方法
前者:刷新之后,还可以继续往文件中写出数据
后者:断开通道,无法再往文件中写数据
字节流和字符流的使用场景
字节流
拷贝任意类型的文件
字符流
读取纯文本文件中的数据
往纯文本文件中写出数据
高级流
缓冲流
字节缓冲流
原理:底层自带了长度为8192的缓冲区提高性能
字节缓冲流提高效率的原理
一次读一个字节
一次读一个数组
字符缓冲流
字符缓冲流的构造方法
字符缓冲流特有的方法
转换流
序列化流(对象操作输出流)
可以把Java中的对象写到本地文件中
序列化流的小细节
使用对象输出流将对象保存到文件时会出现NoSerializableException异常
解决方案
需要让JavaBean类实现Serializable接口
Serializable接口里面是没有抽象方法,标记型接口。
一旦实现这个接口,就表示当前的JavaBean类可以被序列化。
反序列化流(对象操作输入流)
可以把序列化到本地文件中的对象,读取到程序中。
当修改了JavaBean类时,程序在反序列化时就会报错。原因是序列化时生成的版本号(serialVersionUID)与反序列化时的版本号不一致。
解决方案:
//使用以下代码固定版本号
private static final long = 1L;
transient:瞬态关键字
作用:不会把当前属性序列化到本地文件中。
序列化流和反序列化流的细节汇总
打印流
分类:打印流一般是指:PrintStream,PrintWriter两个类
特点1:打印流只操作文件目的地,不操作数据源
特点2:特有的写出方法可以实现,数据原样写出
例如:打印97 文件中:97
打印true 文件中:true
特点3:特有的写出方法,可以实现自动刷新,自动换行
打印一次数据 = 写出+换行+刷新
字节打印流
对于第三个构造方法来说:因为字节流底层没有缓冲区,所以开不开自动刷新都是一样的。
字符打印流
字符流底层有缓冲区,想要自动刷新需要开启。
打印流和输出语句有什么联系
//获取打印流的对象,此打印流在虚拟机启动的时候,由虚拟机创建,默认指向控制台
//特殊的打印流,系统中的标准输出流,不能关闭,在系统中是唯一的。
PrintStream ps = System.out;
//调用打印流中的方法
//写出数据,自动换行,自动刷新
ps.println("123");
//以下写法是将以上代码通过链式编程的方法进行书写
System.out.println();
解压缩流/压缩流
解压缩流
解压本质:把每一个ZipEntry按照层级拷贝到本地另一个文件夹中。
import java.io.File;
public class ZipStreamDemo1{
public static void main(String[] args) throws IOException{
//1.创建一个File表示要解压的压缩包
File src = new File("D:\\aaa.zip");
//2.创建一个File表示解压的目的地
File dest = new File("D:\\");
//调用方法
unzip(src,dest);
}
//定义一个方法用来解压
public static void unzip(File src,File dest) throws IOException{
//解压的本质:把压缩包里面的每一个文件或者文件夹读取出来,按照层级拷贝到目的地当中
//创建一个解压缩流用来读取压缩包中的数据
ZipInputStream zip = new ZipInputStream(new FileInputStream(src));
//要先获取到压缩包里面的每一个zipEntry对象
//表示当前压缩包中获取的文件或者文件夹
ZipEntry entry;
while((entry = zip.getNextEntry()) != null){
System.out.println(entry);
if(entry.isDirectory()){
//文件夹:需要在目的地dest处创建一个同样的文件夹
File file = new File(dest,entry.toString());
file.mkdirs();
}else{
//文件:需要读取到压缩包中的文件,并把他存放到目的地dest文件夹中(按照层级目录进行存放)
FileOutputStream fos = new FileOutputStream(new File(dest,entry.toString()));
int b;
while((b = zip.read())!= -1){
//写到目的地
fos.write(b);
}
fos.close();
//表示在压缩包中一个文件处理完毕
zip.classEntry();
}
}
zip.close();
}
}
压缩流
压缩本质:把每一个(文件/文件夹)看成ZipEntry对象放到压缩包中
//将一个单独的文件变成压缩包
public class ZipStreamDemo2{
public static void main(String[] args)throws IOException{
//1.创建File对象表示要压缩的文件
File src = new File("D:\\a.txt");
//2.创建File对象表示压缩包的位置
File dest = new File("D:\\");
//3.调用方法用来压缩
toZip(src,dest);
}
/*
*作用:压缩
*参数一:表示要压缩的文件
*参数二:表示压缩包的位置
**/
public static void toZip(File src,File dest)throws IOException{
//1.创建压缩流关联压缩包
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(new File(dest,"a.txt")));
//2.创建ZipEntry对象,表示压缩包里面的每一个文件和文件夹
//参数:压缩包里面的路径
ZipEntry entry = new ZipEntry("a.txt");
//3.把ZipEntry对象放到压缩包当中
zos.putNextEntry(entry);
//4.把src文件中的数据写到压缩包当中
FileInputStream fis = new FileInputStream(src);
int b;
while((b = fis.read()) != -1){
zos.write(b);
}
zos.closeEntry();
zos.close();
}
}
//将一个文件夹压缩成一个压缩包
public class ZipStreamDemo3{
public static void main(String[] args) throws IOException{
//1.创建File对象表示要压缩的文件夹
File src = new File("D:\\aaa");
//2.创建File对象表示压缩包放在哪里(压缩包的父级路径)
File destParent = src.getParentFile();//D:\\
//3.创建File对象表示压缩包的路径
File dest = new File(destParent,src.getName()+".zip");
//4.创建压缩流关联压缩包
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(dest));
//5.获取src里面的每一个文件夹,变成ZIPEntry对象,放入压缩包当中
toZip(src,zos,src.getName())
//6.释放资源
zos.close();
}
/*
*作用:获取src里面的每一个文件,变成ZipEntry对象,放入到压缩包当中
*参数一:数据源
*参数二:压缩流
*参数三:压缩包内部的路径
**/
public static void toZip(File src,ZipOutputStream zos,String name) throws IOException{
//1.进入src文件夹
File[] files = src.listFiles();
//2.遍历数组
for(File file:files){
if(file.isFiles){
//3.判段-问及爱你,变成ZipEntry对象,放入到压缩包当中
ZipEntry entry = new ZipEntry(name + "\\" +file.getName());
//读取文件中的数据,写到压缩包
FileInputStream fis = new FileInputStream(file);
int b;
While((b = fis.read()) != -1){
zos.write(b);
}
fis.close();
zos.closeEntry();
}else{
//4.判断-文件夹,递归
toZip(file,zos,name+"\\"+file.getName());
}
}
}
}
Commons-io
Commons-io是Apache开源基金组织提供的一组有关IO操作的开源工具包。
作用:提高IO流的开发效率
Commons-io使用步骤
①在项目中创建一个文件夹:lib
②将jar包复制粘贴到lib文件夹
③右键点击jar包,选择Add as Library ->点击OK
④在类中导包使用
Commons-io常见方法
第二个方法和第三个方法的区别:
前者是直接将源文件夹里面的内容复制到目的文件夹中。后者是将源文件夹整个文件夹复制到目的文件夹里面去。
第四个方法和第五个方法的区别:
前者会把文件夹全部删掉。后者是将文件夹里面的内容清空。