#day12-IO(字符流、Properties)
***
##1. 字符流引入
1. 使用字节流读写字符数据产生的问题
1. 问题1 : 如果写出的是字符数据, 需要将字符数据转换成字节数组.
2. 问题2 : 如果使用字节流读取中文数据, 发生了 `乱码`. 4
2. 集成电路
1. Cpu、内存、硬盘、IO输入输出硬件设备,都是属于集成电路
2. 电子元件 : 只有两种状态,要么开要么关(1和0)
3. 集成电路就是无数个电子元件组合起来的
4. 例子
1. 01001001,8位 -》b -》 ASCII码(1个字节,首位是0,只用7位,故表示128个)
2. encode(编码): 汉语 -> 0101 编码,之后方便计算机存储
3. decode(解码): 0101 -> 汉语 解码,之后方便人类查看
4. messy code(乱码) : 用一种A编码表编码,用B编码表解码
3. 编码表介绍
1. 字节转成字符的规则
2. ascii码表,128个,占一个字节:8位,首位是0,后7位表示 (1个字节)
3. ISO-8859-1(欧码)256个,占一个字节:8位全表示 (1个字节)
4. gbk 2个字节表示1个汉字(windows系统默认)
5. utf8 3个字节表示1个汉字(Java开发主流)
##2. 字符流体系
1. 便捷字符输入流:FileReader
0. 需求:使用便捷字符输入流解决了读取中文乱码的问题
1. 字符流 : 字节流 + 编码表 (字节转字符的规则)
2. FileReader 读取字符文件的便捷类.
3. 特点 : 使用简单,使用该类无需指定编码表
4. 问题: 底层到底有没有编码表??? 有的和平台默认使用编码表一致,GBK
2. 便捷字符输入流:FileWriter
0. 使用便捷字符输出流写入英文与中文到文件中
1. 写出数据时, 字符串无需转换.
2. 写出时无需创建File对象, 也无需指定编码表. 内部使用默认编码表.
3. 字符转换输出流:OutputStreamWriter
0. 需求 : 使用 GBK & UTF-8 写出 hello,我的女神,I love you."
1. OutputStreamWriter(OutputStream out, String charsetName) 使用指定字符集
2. 是字符流通向字节流的桥梁 字符流 = 字节流 + 编码表
3. 字符流的底层是调用字节流读写
4. 多种方式
0. FileWriter writer = new FileWriter(path);
1. new OutputStreamWriter(FileOutputStream fos);
2. OutputStreamWriter(OutputStream out, String charsetName)
4. 字符转换输入流:InputStreamReader
0. 使用InputStreamReader 读取不同编码的文件(GBK、UTF-8)
1. 多种方式
0. FileReader reader = new FileReader(path);
1. InputStreamReader(InputStream in) 创建一个使用默认字符集
2. InputStreamReader(InputStream in, String charsetName) 使用指定字符集
5. 编解码和乱码
1. 编码 encode:将字符数据转换成字节数据. 目的:将字符数据以字节的形式存储到硬盘文件中.
2. 解码 decode:将字节数据转换成字符数据. 目的:将文件中的字节数据转换为字符给程序员查看.
3. 乱码 messy code:以A编码表进行编码, 以B编码表进行解码, 结果就是乱码. (编码表和解码表对应不上就会产生乱码)
##3. 复制文件原理
1. 复制文件的方式
1. Reader & Writer 字符流复制文本文件 :
1. FileReader & FileWriter (使用环境默认编码)
2. InputStreamReader & OutputStreamWriter (手动指定)
2. inputStream & 0utputStream
1. fileInputStream & fileOutputStream
2. 问题:既然字节流和字符流都能复制文件,那它们有何区别?
3. 原理:
1. 字符流在复制过程中需要先编码后解码,效率低。而且在复制图片和音视频文件时也因为编解码的原因,容易造成复制之后的文件产生问题。
2. 字节流复制过程没有编解码,效率高,而且不出错
4. 总结
1. 文件复制应该用字节流
2. 字符流应该用来读写字符数据
## 4. 字符缓冲流
1. BufferedReader & BufferedWriter字符缓冲流
1. BufferedWriter : 接收 Writer.
1. FileWriter(GBK)-> 接收 String / File
2. OutputStreamWriter (UTF-8)-> 接收 OutputStream-> 传递FileOutputStream -> 接收 String / File
3. 缓冲流写出三部曲
1. 写出 2. 换行 3. 刷新
2. BufferedReader -> 接收 Reader
1. FileReader(GBK) -> 接收 String / File
2. InputStreamReade(UTF-8)-> 接收 InputStream -> 传递 FileInputStream -> 接收 String / File
## 5. 其它流
1. 打印流
1. PrintStream
1. printStream 无需手动关闭和刷新, 数据也可以写入到文件中 (自动刷新)
2. PrintStream 为其他输出流添加了功能,使它们能够 `方便地打印各种数据值 print / println` 表示形式。
2. PrintWriter
1. PrintWriter 需要 `启动自动刷新`.
2. 使用场景:网络请求 -> request 请求 PrintWriter writer = request.getPrintWriter(); 作用: 向网页中写出数据.
2. 序列化和反序列化
0. 需求:将一个自定义对象存储到文件中, 并读取出来.
1. 概念
1. 序列化 :将数据结构或对象转换成二进制串的过程
2. 反序列化 :二进制串转换成数据结构或者对象的过程
2. ObjectOutputStream:将Java的对象写入到文件中
1. 异常:NotSerializableException 不能序列化异常
2. 解决:类通过实现 java.io.Serializable 接口以启用其序列化功能
3. Serializable接口
1. 当一个对象要能被序列化,这个对象所属的类必须实现Serializable接口
2. 如果一个接口中没有任何方法, 那么该接口就被称为 `标识接口`
3. ObjectInputStream:将文件中的数据读取为 Java 对象.
1. 异常:InvalidClassException 非法类异常(修改该类)
2. 原因如下:
1. 该类的序列版本号与从流中读取的类描述符的版本号不匹配
2. 该类包含未知数据类型
3. 该类没有可访问的无参数构造方法
3. Serializable标记接口。该接口给需要序列化的类,提供了一个序列版本号serialVersionUID. 该版本号的目的在于验证序列化的对象和对应类是否版本匹配。
4. 解决:在类中显示声明一个该对象的 UID 序列号
* 自动生成,根据该类所有数据计算
4. 瞬态关键字transient
1. 只要被transient修饰的属性,在对象序列化时,这个属性不会被序列化
5. 练习和应用
1. 练习:集合(四大名著:作者) 进行序列化和反序列化
2. 应用:
1. 序列化这个概念太笼统,说白了就是方便计算机表述,使用010101的方式方便传输和存储。
2. java 序列化 也是为了 传输和存储,只是 Serializable 是使用java内部序列化格式。开发中,由于java自身的序列化信息不够简洁,一般很少有使用java 序列化对象进行通信的。
##6. Properties类
1. Properties 类表示了一个持久的属性集。Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。
2. 特点:
1. Hashtable的子类,map集合中的方法都可以用。
2. 该集合没有泛型。键值都是字符串。
3. 它是一个可以持久化的属性集。键值可以存储到集合中,也可以存储到持久化的设备(硬盘、U盘、光盘)上。键值的来源也可以是持久化的设备。
4. 有和流技术相结合的方法。
3. 方法:
1. setProperty(String key, String value):调用 Hashtable 的方法 put
2. stringPropertyNames()返回此属性列表中的键集
3. getProperty(String key)用指定的键在此属性列表中搜索属性
4. store(Writer,comments)和 store(OutputStream,comments)
1. 把集合中的数据,保存到指定的流所对应的文件中,参数comments代表对描述信息
5. load(InputStream) 和load(Reader)
1. 把指定流所对应的文件中的数据,读取出来,保存到Propertie集合中
4. 获取本地系统的属性集
1. Properties prop = System.getProperties() 所有属性集
2. String country = System.getProperty("user.country") 单个属性集
##8. Commons-IO 第三方开源包
1. Apache 软件基金组织 : Commons-IO `通用 IO 包`
2. JAR包
1. (Java Archive,Java 归档文件)是与平台无关的文件格式,它允许将许多文件组合成一个压缩文件。
2. .jar 文件 : 集成了 class 文件. -> class 文件的压缩包.
3. 导开源包的步骤
1. 在工程下创建一个lib文件夹(跟src平级)
2. 复制 .jar文件到lib目录
3. 选中jar包 右单击 -》 build path
4. FileUtils 类 :
1. static void copyFile(File srcFile, File destFile); 复制文件
2. static void copyDirectoryToDirectory(File srcDir, File destDir).复制文件夹
## 9. 流总结
1. "字节流 :"
1. InputStream : 字节输入流
|-- FileInputStream
|-- BufferedInputStream 8k缓存 byte[]
2. OutputStream : 字节输出流
|-- FileOutputStream
|-- BufferedOutputStream
2. "字符流 :"
1. Reader : 字符输入流
|-- InputStreamReader : InputStream + 任意编码表
|-- FileReader : InputStreamReader + 默认编码表 (便捷类) 字节流 + 编码表
|-- BufferedReader
2. Writer : 字符输出流
|-- OutputStreamWriter : OutputStream + 任意编码表
|-- FileWriter : OutputStreamWriter + 默认编码表 (便捷类)字节流 + 编码表
|-- BufferedWriter
3. "请问 : 如何选择使用那种流呢?"
1. "问题1 : 读取字节数据还是字符数据?"
1. 字节 : BufferedInputStream / BufferedOutputStream
2. 字符 : BufferedReader / BufferedWriter
2. "问题2:复制文件用什么流?"
1. 字节流:因为字符流需要编解码,效率低,而且可能出错。
3. "问题3 : 我是读还是写?"
1. 读 : BufferedInputStream / BufferedReader
2. 写 : BufferedOutputStream / BufferedWriter
4. "问题4 : 是否需要高效缓冲呢 ?" 当然要.
1. 是 : 就用对应体系的缓冲流包起来. 缓冲流就是用来装饰其它流的.所以,要加缓冲,就用缓冲流包装其它流
5. "问题5 : 是否需要指定编码表?"
1. 需要 , 转换流. OutputStreamWriter & InputStreamReader
2. 不需要 , 便捷流. FileWriter & FileReader(默认编码)
## 快捷键
1. 程序崩溃, windows -》ctrl + alt + delete -> 任务管理器 -》结束任务
2. 程序失去响应 -》 底部 ,右单机-》启动任务管理器