写在前面:
视频是什么东西,有看文档精彩吗?
视频是什么东西,有看文档速度快吗?
视频是什么东西,有看文档效率高吗?
诸小亮:这一节,我们介绍一下其他不常用的流对象
张小飞:既然不常用,还学习他们干嘛?
诸小亮:虽然不常用,但是偶尔也会用到,技多不压身嘛
Properties
诸小亮:Properties——HashTable的子类,存储键值对,可以把数据持久化到硬盘上
张小飞:哦?这得见识一下
基本演示
诸小亮:它的使用也很简答
public static void main(String[] args) throws IOException {
Properties prop = new Properties();
//1. 存储
prop.put("yase","19");
prop.put("daji","16");
prop.put("change","20");
//2. 遍历
Set<String> names = prop.stringPropertyNames();
for(String name : names){
System.out.println(name + "----" + prop.get(name));
}
//修改数据
//prop.setProperty("daji","18");
}
结果:
诸小亮:需要注意,只有键值都是String时,能使用 stringPropertyNames,否则:
结果:
结果:
张小飞:明白了,不过,您不是说他能把数据持久化到硬盘上吗?
持久化数据
诸小亮:当然了,首先看它的 list 方法
- list:可以把Properties中的数据放到一个 OutputStream 中
public static void main(String[] args) throws IOException {
Properties prop = new Properties();
//1. 存储
prop.put("yase","18");
prop.put("daji","16");
prop.put("change","20");
//把内容输出到System.out中
prop.list(System.out);
}
结果: 注意:** list 方法一般用于测试**
张小飞:不行,这还是没有保存到文件中
诸小亮:看你急的,使用 store 就能存储数据了
public static void main(String[] args) throws IOException {
Properties prop = new Properties();
//1. 存储
prop.put("yase","18");
prop.put("daji","16");
prop.put("change","20");
//2. 把内容输出到文件中
FileOutputStream out = new FileOutputStream("G:\\learn\\hero.properties");
//3. 第一个参数是OutputStream对象,第二个参数是备注
prop.store(out,"hero info");
out.close();
}
结果:
张小飞:原来输出后,key 和 value 用等号连接了起来
诸小亮:是的,其实——properties是 Java 中最常用的配置文件格式
张小飞:那,现在学习 properties 配置文件吗?
诸小亮:no no no,等到学Java的高级框架时候,才会讲这个
读取properties文件
张小飞:既然存到文件中,那么肯定也能从文件中读取吧
诸小亮:当然可以,使用 load 方法
public static void main(String[] args) throws IOException {
Properties prop = new Properties();
FileInputStream in = new FileInputStream("G:\\learn\\hero.properties");
//1. 加载properties文件
prop.load(in);
//2. 遍历
Set<String> names = prop.stringPropertyNames();
for(String name : names){
System.out.println(name + "----" + prop.get(name));
}
in.close();
}
结果:
PrintStream
张小飞:这个 PrintStream 是???
诸小亮:PrintStream——字节打印流,可以把各种类型数据打印到目的地
张小飞:目的地?不是输出到文件中吗?
诸小亮:目的地可以是——File、OutputStream 等对象,包含文件
张小飞:原来是这样
诸小亮:其实我们早就用过这个对象了
张小飞:嗯?什么时候用过?
诸小亮:我们常用的 System.out 就是打印流:
写入文件
诸小亮:我们先尝试使用 PrintStream 往文件中存储数据
public static void main(String[] args) throws IOException {
//1. 创建对象,指定目的地,有两种方式:
PrintStream printStream = new PrintStream("G:\\learn\\hero.txt");
// PrintStream printStream = new PrintStream(new File("G:\\learn\\hero.txt"));
//2. 写入字节数据
printStream.write("yase".getBytes());
//3. 关闭流
printStream.close();
}
结果:
常用方法
write
诸小亮:write(int b)——每次写入一个字节
PrintStream printStream = new PrintStream("G:\\learn\\hero.txt");
//写入字节数据
printStream.write(97);//97对应的是a
printStream.write(353);
//关闭流
printStream.close();
结果:
张小飞:嗯,怎么会这样??????
诸小亮:因为每次只是写入参数的最后一个字节,具体原因:
结果是:aa
第一个 a 是 97,第二个 a 对用353,
97的二进制是:00000000 00000000 00000000 01100001
353转换成二进制是:00000000 00000000 00000001 01100001
因为该方法每次只写入一个字节,97 和 353的最后一个字节一样,所以。。。。。
张小飞:明白了,不过每次只写入一个字节,太扯淡了,不能用这个方法
诸小亮:不错,所以它有提供了另一个方法
write
write(byte b[]):写入字节数组中的所有数据
如果就是想写入 “97” 这两个字符,可以使用这个方法,比如:
结果:
print:可以打印各种类型数据到目的地中
public static void main(String[] args) throws IOException {
//创建对象时,指定目的地,常用的两种方式:
PrintStream printStream = new PrintStream("G:\\learn\\hero.txt");
//打印各种类型数据,println比print多换行功能
printStream.println(true);
printStream.println(97);
printStream.println("yase");
printStream.println(3.14);
printStream.println('c');
//关闭流
printStream.close();
}
结果:
PrintWriter
张小飞:不用说了,PrintWriter——肯定是字符打印流,跟 PrintStream 类似
诸小亮:是的,它们的区别在于——PrintWriter 的 write 方法可以直接写入字符串
ObjectOutputStream
诸小亮:ObjectOutputStream——把 java 对象写入到文件中,称之为:序列化
张小飞:哦?怎么把对象写到文件中?
诸小亮:来,看下面的代码
class Hero {
String name;
public Hero (String name){
this.name = name;
}
@Override
public String toString() {
return "Hero{" +
"name='" + name + '\'' +
'}';
}
}
public static void main(String[] args) throws IOException {
//1. 目的地
FileOutputStream out = new FileOutputStream("G:\\learn\\hero.txt");
//2. 使用ObjectOutputStream封装FileOutputStream
ObjectOutputStream objOut = new ObjectOutputStream(out);
//3. 写入java对象
Hero hero = new Hero("yase");
objOut.writeObject(hero);
//4. 关闭流
objOut.close();
}
结果:
张小飞:您这不是报错了吗?
诸小亮:这时因为 Hero 对象没有实现 Serializable 接口,所以不能序列化
张小飞:Serializable 是什么?
诸小亮:Serializable——序列化标识接口,该接口没有任何方法
诸小亮:但是只有实现Serializable接口的类,才能序列化
张小飞:明白了
诸小亮:修改Hero类,让其实现 Serializable
张小飞:我又运行了一些,虽然没有报错,但是文件打开是这样子的
诸小亮:因为 java 对象不是文本数据,所以使用记事本打开会乱码
ObjectInputStream
诸小亮:ObjectInputStream——从文件中读取对象,称之为:反序列化
public static void main(String[] args) throws IOException, ClassNotFoundException {
//目的地
FileInputStream in = new FileInputStream("G:\\learn\\hero.txt");
ObjectInputStream objIn = new ObjectInputStream(in);
//从文件中读取对象
Hero o = (Hero) objIn.readObject();
System.out.println(o.toString());
}
结果:
张小飞:怎么又报错了? Hero 不是已经实现了 Serializable 接口了吗?
诸小亮:这时因为,缺少一个静态变量serialVersionUI
张小飞:这是????
诸小亮:serialVersionUID: 序列化的版本号,实现Serializable接口,都应该有个这样的静态变量
,
注意:变量的值随意
再次序列化后,再次读取:
transient
张小飞:transient 是什么意思?
诸小亮:transient——瞬态关键字,瞬态:瞬间状态
张小飞:这是干什么的?
诸小亮:如果有些字段不想被序列化到文件中,可以使用这个修饰符,比如:
张小飞:您的意思是,这样 name 字段就不会序列化的文件中了?
诸小亮:是的,使用 transient 后,name字段只存在于内存中,不会被写到文件中
再次运行 序列化 和 反序列化,结果:
ByteArrayInputStream 和 ByteArrayOutputStream
张小飞:这是——字节数组–输入输出流?
诸小亮:是的,其实就是用 IO 的读写思想,操作数组
- ByteArrayInputStream :字节数组输入流,是InputStream的子类
张小飞:什么意思?
诸小亮:之前都是从文件中读取数据,而ByteArrayInputStream,从是字节数组中读取
张小飞:明白了,所以创建对象时,要传递一个字节数组进去
诸小亮:是的,另外还有 ByteArrayOutputStream
- ByteArrayOutputStream :字节数组输出流,是 OutputStream 的子类
- 作用:把数据写到其内部的一个 byte 数组中
张小飞:那是一个可变数组吧
诸小亮:不错,内部的数组会随着数据的不断写入而自动增长
张小飞:能演示一下吗?
诸小亮:当然可以
public static void main(String[] args) throws IOException, ClassNotFoundException {
ByteArrayInputStream bin = new ByteArrayInputStream("yase".getBytes());
ByteArrayOutputStream bout = new ByteArrayOutputStream();
int ch =0;
//从ByteArrayInputStream读出,写到ByteArrayOutputStream中
while((ch = bin.read()) != -1){
//写入内部数组中
bout.write(ch);
}
//获取ByteArrayOutputStream中的数据
System.out.println(bout.toString());
}
张小飞:您没有关闭流对象
诸小亮:这两对象操作的都是内存,比较特殊,所以不用close
张小飞:明白了