序列化与反序列化
序列化
概念
序列化:指将程序中的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;}@Overridepublic 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();}}}}
