序列化与反序列化

序列化

概念

序列化:指将程序中的Java对象,永久保存到磁盘中,相当于写出的过程

对应流方向:out,对应序列化流为ObjectOutputStream

利用ObjectOutputStream,把对象的信息,按照固定的格式转成一串字节值输出并持久保存到磁盘

反序列化

概念

反序列化:指将已经序列化的在文件中保存的数据,读取/恢复到程序中

对应流方向:in,对应反序列化流为ObjectInputStream

利用ObjectInputStream,读取磁盘中之前序列化好的数据,重新恢复成对象

特点与应用场景

  1. 需要序列化的文件必须实现Serializable接口,用来启用序列化功能
  2. 不需要序列化的数据可以修饰成static,原因:static资源属于类资源,不随着对象被序列化输出
  3. 每一个被序列化的文件都有一个唯一的id,如果没有添加此id,编译器会自动根据类的定义信息计算产生一个
  4. 在反序列化时,如果和序列化的版本号不一致,无法完成反序列化
  5. 常用与服务器之间的数据传输,序列化成文件,反序列化读取数据
  6. 常用使用套接字流在主机之间传递对象
  7. 不需要序列化的数据也可以被修饰成transient(临时的),只在程序运行期间在内存中存在,不会被序列化持久保存

使用的流对象

ObjectOutputStream:序列化

ObjectOutputStream 将 Java 对象的基本数据类型写入 OutputStream,通过在流中使用文件可以实现对象的持久存储。如果流是网络套接字流,则可以在另一台主机上或另一个进程中重构对象。

构造方法:ObjectOutputStream(OutputStream out)

创建写入指定 OutputStreamObjectOutputStream

  1. ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(new File("F:\\ready\\1.txt")));

普通方法:writeObject(Object obj)

将指定对象写入ObjectOutputStream

  1. 对象名.weiteObject(需要序列化的对象名);
  2. outputStream.writeObject(student);

ObjectInputStream:反序列化

ObjectInputStream对以前使用ObjectOutputStream写入的基本数据和对象进行反序列化重构对象。

构造方法:
ObjectInputStream(InputStream in) 创建从指定 `InputStream读取的ObjectInputStream

普通方法:
readObject()ObjectInputStream 读取对象

  1. ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(new File("F:\\ready\\1.txt")));
  1. Object 对象名 = 反序列化的对象名.readObject();
  2. Object o = inputStream.readObject();

示例代码

创建序列化对象

  1. package cd.tedu.serializable;
  2. import java.io.Serializable;
  3. /**
  4. * 封装学生对象,用于测试序列化
  5. * 若想要完成序列化,必须实现可序列化接口,否则报错
  6. * 报错信息
  7. * java.io.NotSerializableException: cd.tedu.serializable.Student
  8. * Serializable接口为空接口,其中不存在方法
  9. * 作用:用于当作标记,标记这个类的对象可以被序列化输出
  10. */
  11. public class Student implements Serializable {
  12. private static final long serialVersionUID = 250L;
  13. private String name;
  14. private int age;
  15. private String address;
  16. private char gender;
  17. private int id;
  18. public Student() {
  19. System.out.println("无惨");
  20. }
  21. public Student(String name, int age, String address, char gender) {
  22. System.out.println("群惨");
  23. this.name = name;
  24. this.age = age;
  25. this.address = address;
  26. this.gender = gender;
  27. }
  28. public String getName() {
  29. return name;
  30. }
  31. public void setName(String name) {
  32. this.name = name;
  33. }
  34. public int getAge() {
  35. return age;
  36. }
  37. public void setAge(int age) {
  38. this.age = age;
  39. }
  40. public String getAddress() {
  41. return address;
  42. }
  43. public void setAddress(String address) {
  44. this.address = address;
  45. }
  46. public char getGender() {
  47. return gender;
  48. }
  49. public void setGender(char gender) {
  50. this.gender = gender;
  51. }
  52. @Override
  53. public String toString() {
  54. return "Student{" +
  55. "name='" + name + '\'' +
  56. ", age=" + age +
  57. ", address='" + address + '\'' +
  58. ", gender=" + gender +
  59. '}';
  60. }
  61. }

将Student类进行序列化与反序列化

  1. package cd.tedu.serializable;
  2. import java.io.*;
  3. /**
  4. * 测试序列化与反序列化
  5. * 序列化:指将程序中的Java对象,永久保存到磁盘中,相当于写出的过程
  6. * 对应流方向:out,对应序列化流为ObjectOutputStream
  7. * 反序列化:指将已经序列化的在文件中保存的数据,读取/恢复到程序中
  8. * 对应流方向:in,对应反序列化流为ObjectInputStream
  9. */
  10. public class TestSerializable {
  11. public static void main(String[] args) {
  12. method();//测试序列化
  13. method1();//测试反序列化
  14. }
  15. private static void method() {
  16. ObjectOutputStream outputStream =null;
  17. try {
  18. //ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(new File("F:\\ready\\1.txt")));
  19. outputStream = new ObjectOutputStream(new FileOutputStream("F:\\ready\\1.txt"));
  20. Student student = new Student("埼玉",22,"广岛",'男');
  21. outputStream.writeObject(student);
  22. System.out.println("恭喜你!序列化成功");
  23. } catch (IOException e) {
  24. e.printStackTrace();
  25. System.out.println("很抱歉!序列化失败");
  26. } finally {
  27. try {
  28. outputStream.close();
  29. } catch (IOException e) {
  30. e.printStackTrace();
  31. }
  32. }
  33. }
  34. private static void method1() {
  35. ObjectInputStream inputStream = null;
  36. try {
  37. //inputStream = new ObjectInputStream(new FileInputStream(new File("F:\\ready\\1.txt")));
  38. inputStream = new ObjectInputStream(new FileInputStream("F:\\ready\\1.txt"));
  39. Object o = inputStream.readObject();
  40. System.out.println(o);
  41. System.out.println("反序列化成功");
  42. } catch (Exception e) {
  43. System.out.println("反序列化失败");
  44. e.printStackTrace();
  45. }finally {
  46. try {
  47. inputStream.close();
  48. } catch (IOException e) {
  49. e.printStackTrace();
  50. }
  51. }
  52. }
  53. }

报错信息

NotSerializableException

原因:要序列化对象所在的类并没有实现序列化接口

解决方法:实现序列化接口

  1. public class 类名 implements Serializable {}

InvalidClassException:

原因:本次反序列化时使用的UID与序列化时的UID不匹配

解决方法:反序列化时的UID与序列化时的UID要保持一致,或者测试时一次序列操作对应一次反序列化操作,否则不匹配就报错

  1. private static final long serialVersionUID = uid编号;

文件复制

示例代码

  1. package cd.tedu.io;
  2. import java.io.*;
  3. import java.util.Scanner;
  4. public class TestCopyFile {
  5. public static void main(String[] args) {
  6. System.out.print("请输入要复制的文件路径:");
  7. String f = new Scanner(System.in).nextLine();
  8. System.out.print("请输入目标文件路径:");
  9. String t = new Scanner(System.in).nextLine();
  10. ZFCopy(f,t);//字符流文件复制
  11. ZJCopy(f,t);//字节流文件复制
  12. }
  13. private static void ZFCopy(String f, String t) {
  14. Reader in = null;
  15. Writer out = null;
  16. try {
  17. in = new BufferedReader(new FileReader(f));
  18. out = new BufferedWriter(new FileWriter(t));
  19. int b;
  20. while ((b = in.read()) != -1){
  21. System.out.println(b);
  22. out.write(b);
  23. out.flush();
  24. }
  25. System.out.println("复制成功");
  26. } catch (Exception e) {
  27. System.out.println("复制失败");
  28. e.printStackTrace();
  29. } finally {
  30. /*
  31. 关流顺序:最后创建的流先关闭,多条关流语句需要各自try-catch
  32. */
  33. try {
  34. out.close();
  35. } catch (IOException e) {
  36. e.printStackTrace();
  37. }
  38. try {
  39. in.close();
  40. } catch (IOException e) {
  41. e.printStackTrace();
  42. }
  43. }
  44. }
  45. private static void ZJCopy(String f, String t) {
  46. InputStream in = null;
  47. OutputStream out = null;
  48. try {
  49. in = new BufferedInputStream(new FileInputStream(f));
  50. out = new BufferedOutputStream(new FileOutputStream(t));
  51. int b;
  52. while ((b = in.read()) != -1){
  53. System.out.println(b);
  54. out.write(b);
  55. }
  56. System.out.println("复制成功");
  57. } catch (Exception e) {
  58. System.out.println("复制失败");
  59. e.printStackTrace();
  60. } finally {
  61. try {
  62. out.close();
  63. } catch (IOException e) {
  64. e.printStackTrace();
  65. }
  66. try {
  67. in.close();
  68. } catch (IOException e) {
  69. e.printStackTrace();
  70. }
  71. }
  72. }
  73. }