文章目录
1 序列化和反序列化
有如下需求:
-
将
int num = 100
,这个数据保存到文件中,需要同时保存数据类型 int,并且还需要能够从文件中直接恢复为 int 100 -
将
Dog dog = new Dog("小黄", 3)
这个dog
对象保存到文件中,并且能够从文件中恢复。
完成如上的要求,我们可以使用序列化的特性。
序列化和反序列化
序列化:就是在保存数据的时,保存数据的值和数据类型
反序列化:就是在恢复数据时,恢复数据的值和数据类型
注意: 需要让某个对象支持序列化机制,则必须让其类是可序列化的,为了让某个类是可序列化的该类必须实现如下2个接口之一:
Serializable
:这是一个标记接口,没有方法Externalizable
:该接口有方法需要实现,因此在使用时,一般使用Serializable
接口
2 对象流
对象流: 提供了对基本数据类型或对象类型的序列化和反序列化的方法
ObjectOutputStream
提供 序列化功能
ObjectInputStream
提供 反序列化功能
2.1 ObjectOutputStream 介绍
ObjectOutputStream
类的继承、实现关系如下图:
案例讲解: 使用 ObjectOutputStream
序列化基本数据类型和一个 Dog
对象,并保存到 data.dat
文件中。
import java.io.*;
public class ObjectOutput1_ {
public static void main(String[] args) throws IOException {
//序列化后,保存的文件格式,不是纯文本
//而是按照指定格式要求 .dat
ObjectOutputStream objectInputStream = new ObjectOutputStream(new FileOutputStream("d:\\0\\data.dat"));
//int->Integer (实现了 Serializable)
objectInputStream.writeInt(3);
//boolean-> Boolean (实现了 Serializable)
objectInputStream.writeBoolean(true);
// char-> Character (实现了 Serializable)
objectInputStream.writeChar('a');
//double-> Double (实现了 Serializable)
objectInputStream.writeDouble(22.4);
objectInputStream.writeObject(new Dog());
objectInputStream.close();
}
}
class Dog implements Serializable{
}
2.2 ObjectInputStream 的介绍
ObjectInputStream
类的继承、实现关系如下图:
案例讲解: 使用 ObjectInputStream 读取 data.dat 并反序列化恢复数据。
注意: data.dat 中的数据在反序列化时,需要按照当初序列化的数据的顺序进行,不然反序列化将会失败。
package object_;
import java.io.*;
public class ObjectInput1_ {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("d:\\0\\data.dat"));
//注意顺序
System.out.println(inputStream.readInt());
System.out.println(inputStream.readBoolean());
System.out.println(inputStream.readChar());
System.out.println(inputStream.readDouble());
System.out.println(inputStream.readObject());
inputStream.close();
}
}
2.3 对象流的注意事项
- 读写顺序要一致,即元素序列化的顺序,要和反序列化的顺序一致。
- 要求序列化或反序列化对象,则该对象的类需要实现 Serializable 。
- 序列化的类中建议添加 SerialVersionUID,为了提高版本的兼容性。
- 序列化对象时,默认将里面所有属性都进行序列化,但除了 static 或 transient 修饰的成员
- 序列化对象时,要求里面的属性类型也需要实现序列化接口
- 序列化具备可继承性,也就是如果某类实现了序列化,则它的所有子类也已经默认实现了序列化。
3 标准输入输出流
流 | 类型 | 用途 | 常见包装类 |
---|---|---|---|
System.in | InputStream | 读取输入(如键盘) | Scanner , BufferedReader |
System.out | PrintStream | 输出正常信息(控制台) | 直接使用 |
System.err | PrintStream | 输出错误信息 | 直接使用 |
正如我们平常使用的一样:
Scanner in = new Scanner(System.in);
System.out.println();
4 转换流
转换流: InputStreamReader
和 OutputStreamWriter
InputStreamReader
:Reader
的子类,可以将InputStream
(字节流)包装成(转换)Reader
(字符流)OutputStreamWriter
:Writer
的子类,实现将OutputStream
(字节流)包装成Writer
(字符流)- 当处理纯文本数据时,如果使用字符流效率更高,并且可以有效解决中文乱码问题,所以建议将字节流转换成字符流。
- 可以在使用时指定编码格式(比如:
utf-8
、gbk
等)
InputStreamReader
的构造方法:
OutputStreamWriter
的构造方法:
由上可以看出,这2个类的构造方法,都存在支持指定编码方式的重载。
案例讲解: 使用 InputStreamReader
进行输入,并指定编码方式。
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
public class InputStreamReader_ {
public static void main(String[] args) throws IOException {
//1.创建FileInputStream对象
// FileInputStream fileInputStream = new FileInputStream("d:\\0\\second.txt");
//2.创建InputStreamReadre对象,并指定编码方式
// InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "gbk");
//3.创建BufferedReader对象进行输入
//BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
//将前面所有步骤合在一起
BufferedReader br = new BufferedReader(new InputStreamReader((new FileInputStream ("d:\\0\\second.txt")), "gbk"));
String s = br.readLine();
System.out.println(s);
br.close();
}
}
5 打印流
打印流: PrintStream 和 PrintWriter
注意: 打印流只有输出流,没有输入流
案例演示: 使用 PrintWriter
进行打印输出。
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
public class PrintWriter_ {
public static void main(String[] args) throws IOException {
//输出到控制台
PrintWriter printWriter = new PrintWriter(System.out);
//输出到文件 second.txt
PrintWriter printWriter1 = new PrintWriter(new FileWriter("d:\\0\\second.txt"));
printWriter.write('a');//输出到控制台
printWriter1.write(8);//输出到second.txt文件里
printWriter.close();
printWriter1.close();
}
}
案例演示: 使用PrintStream
进行打印输出。
import java.io.FileNotFoundException;
import java.io.PrintStream;
public class PrintStream_ {
public static void main(String[] args) throws FileNotFoundException {
PrintStream printStream = System.out;
printStream.print(6);
//因为print 底层使用的是write,
// 所以我们可以直接调用write进行打印/输出
printStream.write('9');
//我们可以去修改打印流输出的位置/设备
//1. 输出修改成到 "d:\\0\\second.txt"
//2. "6" 和 "9" 就会输出到 "d:\\0\\second.txt"
//3. public static void setOut(PrintStream out) {
// checkIO();
// setOut0(out); // native 方法,修改了 out
// }
//使用SetOut() 方法
System.setOut(new PrintStream("d:\\0\\second.txt"));
System.out.println('t');
printStream.close();
}
}