序列化与反序列化
序列化
概念
序列化:指将程序中的Java对象,永久保存到磁盘中,相当于写出的过程
对应流方向:out,对应序列化流为ObjectOutputStream
利用ObjectOutputStream,
把对象的信息,按照固定的格式转成一串字节值输出并持久保存到磁盘
反序列化
概念
反序列化:指将已经序列化的在文件中保存的数据,读取/恢复到程序中
对应流方向:in,对应反序列化流为ObjectInputStream
利用ObjectInputStream
,读取磁盘中之前序列化好的数据,重新恢复成对象
特点与应用场景
- 需要序列化的文件必须实现Serializable接口,用来启用序列化功能
- 不需要序列化的数据可以修饰成static,原因:static资源属于类资源,不随着对象被序列化输出
- 每一个被序列化的文件都有一个唯一的id,如果没有添加此id,编译器会自动根据类的定义信息计算产生一个
- 在反序列化时,如果和序列化的版本号不一致,无法完成反序列化
- 常用与服务器之间的数据传输,序列化成文件,反序列化读取数据
- 常用使用套接字流在主机之间传递对象
- 不需要序列化的数据也可以被修饰成transient(临时的),只在程序运行期间在内存中存在,不会被序列化持久保存
使用的流对象
ObjectOutputStream:序列化
ObjectOutputStream
将 Java 对象的基本数据类型写入 OutputStream
,通过在流中使用文件可以实现对象的持久存储。如果流是网络套接字流,则可以在另一台主机上或另一个进程中重构对象。
构造方法:ObjectOutputStream(OutputStream out)
创建写入指定 OutputStream
的 ObjectOutputStream
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(new File("F:\\ready\\1.txt")));
普通方法:writeObject(Object obj)
将指定对象写入ObjectOutputStream
对象名.weiteObject(需要序列化的对象名);
outputStream.writeObject(student);
ObjectInputStream:反序列化
ObjectInputStream
对以前使用ObjectOutputStream
写入的基本数据和对象进行反序列化重构对象。
构造方法:
ObjectInputStream(InputStream in)
创建从指定`InputStream
读取的ObjectInputStream
普通方法:
readObject()
从ObjectInputStream
读取对象
ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(new File("F:\\ready\\1.txt")));
Object 对象名 = 反序列化的对象名.readObject();
Object o = inputStream.readObject();
示例代码
创建序列化对象
package cd.tedu.serializable;
import java.io.Serializable;
/**
* 封装学生对象,用于测试序列化
* 若想要完成序列化,必须实现可序列化接口,否则报错
* 报错信息
* java.io.NotSerializableException: cd.tedu.serializable.Student
* Serializable接口为空接口,其中不存在方法
* 作用:用于当作标记,标记这个类的对象可以被序列化输出
*/
public class Student implements Serializable {
private static final long serialVersionUID = 250L;
private String name;
private int age;
private String address;
private char gender;
private int id;
public Student() {
System.out.println("无惨");
}
public Student(String name, int age, String address, char gender) {
System.out.println("群惨");
this.name = name;
this.age = age;
this.address = address;
this.gender = gender;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public char getGender() {
return gender;
}
public void setGender(char gender) {
this.gender = gender;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", address='" + address + '\'' +
", gender=" + gender +
'}';
}
}
将Student类进行序列化与反序列化
package cd.tedu.serializable;
import java.io.*;
/**
* 测试序列化与反序列化
* 序列化:指将程序中的Java对象,永久保存到磁盘中,相当于写出的过程
* 对应流方向:out,对应序列化流为ObjectOutputStream
* 反序列化:指将已经序列化的在文件中保存的数据,读取/恢复到程序中
* 对应流方向:in,对应反序列化流为ObjectInputStream
*/
public class TestSerializable {
public static void main(String[] args) {
method();//测试序列化
method1();//测试反序列化
}
private static void method() {
ObjectOutputStream outputStream =null;
try {
//ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(new File("F:\\ready\\1.txt")));
outputStream = new ObjectOutputStream(new FileOutputStream("F:\\ready\\1.txt"));
Student student = new Student("埼玉",22,"广岛",'男');
outputStream.writeObject(student);
System.out.println("恭喜你!序列化成功");
} catch (IOException e) {
e.printStackTrace();
System.out.println("很抱歉!序列化失败");
} finally {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static void method1() {
ObjectInputStream inputStream = null;
try {
//inputStream = new ObjectInputStream(new FileInputStream(new File("F:\\ready\\1.txt")));
inputStream = new ObjectInputStream(new FileInputStream("F:\\ready\\1.txt"));
Object o = inputStream.readObject();
System.out.println(o);
System.out.println("反序列化成功");
} catch (Exception e) {
System.out.println("反序列化失败");
e.printStackTrace();
}finally {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
报错信息
NotSerializableException
原因:要序列化对象所在的类并没有实现序列化接口
解决方法:实现序列化接口
public class 类名 implements Serializable {}
InvalidClassException:
原因:本次反序列化时使用的UID与序列化时的UID不匹配
解决方法:反序列化时的UID与序列化时的UID要保持一致,或者测试时一次序列操作对应一次反序列化操作,否则不匹配就报错
private static final long serialVersionUID = uid编号;
文件复制
示例代码
package cd.tedu.io;
import java.io.*;
import java.util.Scanner;
public class TestCopyFile {
public static void main(String[] args) {
System.out.print("请输入要复制的文件路径:");
String f = new Scanner(System.in).nextLine();
System.out.print("请输入目标文件路径:");
String t = new Scanner(System.in).nextLine();
ZFCopy(f,t);//字符流文件复制
ZJCopy(f,t);//字节流文件复制
}
private static void ZFCopy(String f, String t) {
Reader in = null;
Writer out = null;
try {
in = new BufferedReader(new FileReader(f));
out = new BufferedWriter(new FileWriter(t));
int b;
while ((b = in.read()) != -1){
System.out.println(b);
out.write(b);
out.flush();
}
System.out.println("复制成功");
} catch (Exception e) {
System.out.println("复制失败");
e.printStackTrace();
} finally {
/*
关流顺序:最后创建的流先关闭,多条关流语句需要各自try-catch
*/
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static void ZJCopy(String f, String t) {
InputStream in = null;
OutputStream out = null;
try {
in = new BufferedInputStream(new FileInputStream(f));
out = new BufferedOutputStream(new FileOutputStream(t));
int b;
while ((b = in.read()) != -1){
System.out.println(b);
out.write(b);
}
System.out.println("复制成功");
} catch (Exception e) {
System.out.println("复制失败");
e.printStackTrace();
} finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}