1、笔记整理
/**
* IO流的学习
* 1、IO定义
* Input/Output的简称
*
* 2、流的分类
* 按操作数据单位不同分为: 字节流(8bit),字符流(16bit)
* 字节流一般操作图片、视频、音频等二进制文件
* 字符流一般操作文件.java、.txt、.xml等
* 按数据流的流向不同分为:输入流和输出流
*
* 按流的角色的不同分为:节点流和处理流
* 已有流作为另一个流的构造参数,外层流称为处理流,处理流有很多种,不用的处理流有不同的作用。
* 已有流称为节点流。
* 3、流的4个抽像基类
* 字节流两个:InputStream、OutputStream
* 字符流两个:Reader、Writer
*
* 该四个基类的子类的命名都是以四个基类名作为当前子类命名的后缀
* 例如FileInputStream 是一个自己输入流
* 要求能根据不同流的名称能判断出来该流是输入还是输出流,是字节流还是字符流,是节点流还是处理流
*
* 4、字符流
* 对于文本文件(.txt、.java、.xml) 可以使用字符流来处理
* 1、FileReader
* 把文件内容加载到内存中并打印出来
*
* read() 该方法每次从文本里面读一个字符,如果读到了-1就说明最后一个字符读完了
* 读的次数比字符的次数多一个
*
* read(char[] char); 该方法每次可以从文本文件中读的字符个数是 数组的长度。并且返回值是每次
* 放到数组中的字符个数
* 2、FileWriter
* 从内存中写出内存中的内容到指定的文件中.
* 要输出的文件可以不存在,如果不存在就创建。
* 如果要存在 可能会覆盖原有文件。看你选在那个构造器了
* fileWriter = new FileWriter(file,true); 这里不会覆盖
* fileWriter = new FileWriter(file); 这里会覆盖
*
* 输出
* fileWriter.write("you need to have a dream");
*
*
* 5、字节流
* .jpg、.mp3、.mp4、.doc、.ppt 都是可以使用字节流来处理
*
* read(byte[] char); 该方法每次可以从二进制文件中读的字节个数是 字节数组的长度。并且返回值是每次
* 放到数组中的字节个数
* 6、缓冲流
* 缓冲流是处理流的一种,是对节点流的一个包转,读写效率要好,开发时一般考虑用缓冲流,一般不会用
* 字点流。
*
*
* 字节流
* BufferedInputStream bufferedInputStream = new BufferedInputStream(fis);
* BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fio);
*
* 读入数据
* read(bytes)
* 该方法每次可以从二进制文件中读的字节个数是 字节数组的长度。并且返回值是每次
* 放到数组中的字节个数
* 写出数据
* bufferedOutputStream.write(bytes,0,len);
* 写出去的字节数量,数组中第0个位置开始,取len个。
*
* 关闭流
* 要求:先关闭处理流再关闭节点流
* 关闭处理流的时候,节点流也会自定的关闭了。
*
*
* 字符流
* BufferedReader bufferedReader = new BufferedReader(fileReader);
* BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
*
* 读入数据
* 方式一
* bufferedReader.read(chars);
* 该方法每次可以从文本文件中读的字符个数是 字节数组的长度。并且返回值是每次
* 读的并且放到数组中的个数
* 方式二
* String data = bufferedReader.readLine();
* bufferedWriter.write(data + "\n");
* bufferedReader.readLine()
* 该方式是每次读一行,但是不包括 每一行的换行符,
* 写的时候如果不手动加换行符就是在目标文件里写一行
* 或者按如下的方式
* bufferedWriter.write(data);
* bufferedWriter.newLine(); //提供换行的操作
*
* 写出数据
* bufferedWriter.write(chars,0,len);
* 写出去的字节符数量,数组中第0个位置开始,取len个。
*
* 关闭流
* 要求:先关闭处理流再关闭节点流
* 关闭处理流的时候,节点流也会自定的关闭了。
*
* 7、转换流
* InputStreamReader 和 OutputStreamWriter
* 这两个处理流是属于字符流,操作的是字符。
* InputStreamReader:将一个字节输入流转换为字符输入流
* OutputStreamWriter:将一个字符输出流转换为一个字节输出流
* 作用:
* 提供字节流和字符流之间的转换
*
* 解码和编码的理解
* 解码:字节、字节数组-----> 字符、字符串。看不懂到看懂叫解码
* InputStreamReader
* 编码:字符、字符串------>字符、字符数组。由看的懂到看不懂
* OutputStreamWriter
*
* 字符集
*
* 使用场景
* 用字节流读取文本文件的时候,需要把读的内容打印出来,例如日志、控制台此时就需要转换流了,
* 否则在展示时会有乱码的发生。
*
*
* InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream,"UTF-8");
* 创建流时需要指定以什么样的字符编码展示文本内容,字符集需要根据文本存的时候指定
* 的字符集编码了
* file -I course.sql 看文件的编码格式 mac
* file -i course.sql Linux环境看编码格式
* OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream,"gbk");
* 创建流时需要指定以什么样的字符编码来写入某个文本文件
* 这里就可以随意的指定字符编码格式了
*
* 8、字符集的统一说明
* 1、编码表的由来
* 计算机只能识别二进制数据,为了方便应用计算机,让它能识别各个国家的文字。就讲各个国家的文字用数字来表示
* ,并一一对应,形成一张表,这就是编码表
* 2、作用
* 解码和编码的依据,类似于一个密码本,依据字符集把二进制解码成能看懂的语言。
* 2、常见的编码表
* ASCII:美国标准信息交换码,用一个字节的7位表示 2^7次方 128 个情况。
* 对美国来讲用ASCII码表 进行解码和编码就够用了。美国是拼音文字,大小写标点等加起来
* 128个情况可以满足要求
* ISO8859-1:拉丁码表,欧洲码表 用一个字节的 8 位来表示 2^8 次方 256个情况
* GB2312:中国的中文码表。最多两个字节编码所有文字
* GBK:中国的中文码升级表。融合了更多的中文文字符号。最多两个字节编码所有文字
* GBK、GB2312在用两个字节表示一个汉字时,字节里面如果开头是1 表示要用两个字节表示一个汉字
* 如果是0 开头就说明该字节表示单独的一个汉字
* Unicode:国际标准码,融合了目前人类所用的字符。为每一个字符分配唯一的字符码。所有的文字都用两个字节表示
* 也就是 2^16 次方。就可以把所有的字符表示起来。
* 但是也会存在和GBK、GB2312 一样的问题。这样的问题如果用 1、0 来区别 当前字节表示一个字符
* 还是一个字符中的一部分呢,但是这样 的化,情况就变成了2^15 次方,导致不够用,不能把所有的字符
* 都包含进来。
* 另外一个问题英文字母用一个字节表示就行,两个字节造成浪费。
*
* Unicode 和 UTF-8的关系
* Unicode 只是定义了字符的集合和字符的唯一编码。
* 编码在用二进制表示的时候按照UTF-8的规则来表示。
* UTF-8 规则来确定字符是用一个字符表示还是两个字符表示还是三个字符表示。
* UTF-8是Unicode的落地方案。
* 9、对象流
* ObjectOutputStream objectOutputStream 和 ObjectInputStream objectInputputStream
*
* 满足以下要求才能把类序列化
* 1、实现Serializable 接口,表示当前类是可以序列化的
* 2、需要当前类需要提供一个全局常量 serialVersionUID(自己随便定义值)
* private static final long serialVersionUID = 23342232320887L;
* 3、除了当前类需要实现Serializable接口,当前类的属性也要保证能序列化,基本数据类型
* 和String 都是可以序列化的
*
* serialVersionUID的理解
* 序列号的目的是在反序列化的时候能找到当前类,如果不手动声明一个序列号,在序列化时也会自动
* 的生成一个序列号。但是如果序列化对象后,修改了类此时就不能反序列化了
* Book book = (Book) objectInputputStream.readObject();
* 此时会报错
* java.io.InvalidClassException:
* 如果我们自己手动的添加了序列号就不会出现错误。
*
* 一般情况
* 一般情况我们前后台交互的时候会通过JSON来交互,JSON是一个字符串,字符串默认是可以序列化的
*
*
*
* 9、注意实现
* 1、如果流在创建时,指定的文件或文件路径不存在会报错 (No such file or directory)
* 创建file实例时不会报错。
* 字节流读取文本文件如果文本文件中有中文会乱码,没有中文的话是可以的,但是不建议用字节流。
*
* 2、处理流在close时
* 会自动的调用flush方法,把缓存里面缓存的数据刷到我们指定的文件里.
* close()方法进去就能看到了。
* 所以我们一般不用手动的flush。
*
*
*
*
*
*
*
*/
2、使用缓冲流复制二进制文件
public class HCLTest {
@Test
public void test(){
long l = System.currentTimeMillis();
fileCopy("/Users/fanmei/Downloads/VMware_Fusion_Pro_11.5.6__macwk.com.dmg","/Users/fanmei/Desktop/ss.dmg");
long end = System.currentTimeMillis();
System.out.println( "花费了" + (end - l));
}
public void fileCopy(String src,String dest){
//1、实例File 对象,用该对象表示要操作的图片
//File file = new File("src/main/resources/tems/static/赵奕欢.jpg");
File file = new File(src);
//File file1 = new File("/Users/fanmei/赵奕欢.jpg");
File file1 = new File(dest);
FileInputStream fis = null;
FileOutputStream fio = null;
BufferedInputStream bufferedInputStream = null;
BufferedOutputStream bufferedOutputStream = null;
try {
//2、准备节点流
fis = new FileInputStream(file);
fio = new FileOutputStream(file1);
//3、准备处理流
bufferedInputStream = new BufferedInputStream(fis);
bufferedOutputStream = new BufferedOutputStream(fio);
//这里注意使用字节数组
byte[] bytes = new byte[1024];
int len = 0;
//4、操作文件
while (len > -1){
//返回的是 每次读入到数组中的字节个数,如果返回的是 -1 证明从文件里面读不到数据了
len = bufferedInputStream.read(bytes);
bufferedOutputStream.write(bytes);
}
}catch (IOException e){
e.printStackTrace();
}finally {
//5、关闭处理流
if(bufferedInputStream != null){
try {
bufferedInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(bufferedOutputStream != null){
try {
bufferedOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}