概念

作用 :可以把Java中对象直接写到文件中 ,把对象写到文件的过程,也叫序列化
也可以把文件中的对象(一定是通过对象流写进去的)读出来,读出来之后,直接就是对象
对象必须实现序列化的接口 java.io.Serializable 这个接口是一个标识接口 实现了这个接口的类,表示可以被序列化
例如 :
public class User implements Serializable {
private int id;
private String username ;
private String password ;
private int age ;
private Date birth;
//省略 各种 自动生成方法
}

1. 对象输出流

ObjectOutputStream :对象输出流 ,输出Java对象的时候,对象必须实现了 Serializable接口 ,通过JDK提供的一种序列化方式写入文件 ,这个文件最好是二进制文件
对象流 - 图1
public class TestObjStream {
public static void main(String[] args) {
User user = new User(1, “admin”, “123456”, 22, new Date());

//E:/woniu/57/JavaSE/day19/user.dat
//把上述 user 对象 写到 user.dat文件中
File f = new File(“E:/woniu/57/JavaSE/day19/user.dat “);

ObjectOutputStream oos = null;

try {
oos = new ObjectOutputStream(new FileOutputStream(f));
//写对象
oos.writeObject(user);

} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
try {
oos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

2.对象输入流

ObjectInputStream :从文件把Java中的对象 读取出来 到内存 这个对象也要实现 Serializable
对象流 - 图2
读数据 :
public class TestObjectInput {
public static void main(String[] args) {

//E:/woniu/57/JavaSE/day19/user.dat
File f = new File(“E:/woniu/57/JavaSE/day19/user.dat”);

ObjectInputStream ois = null;

try {
ois = new ObjectInputStream(new FileInputStream(f));
//读数据
User user = (User) ois.readObject();
System.out.println(user);

} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
try {
ois.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

}
}

  1. 在读数据的时候,经常会遇到这个异常 :

对象流 - 图3
此异常的处理方案:

  1. 每次向文件写数据的时候,在最后写一个 null 值 到文件 ,读数据的时候,遇到null 就不在读取数据
  2. 捕获EOFException 异常 ,一旦捕获到这个异常 就代表数据读取结束
  3. 序列化的编号 当我们把一个对象 写进文件 以后,修改了实体对象 ,执行读数据的时候,报下面的错误:java.io.InvalidClassException: com.woniu.day19.entity.User; local class incompatible: stream classdesc serialVersionUID = -8553620651819186625, local class serialVersionUID = -8597985291820613233
    at java.io.ObjectStreamClass.initNonProxy(Unknown Source)
    at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
    at java.io.ObjectInputStream.readClassDesc(Unknown Source)
    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.readObject(Unknown Source)
    at com.woniu.day19.obj.TestObjectInput.main(TestObjectInput.java:22)问题的解决方案 :在创建实体对象的时候, 指定序列化编码,定死了序列化编码public class User implements Serializable {
    /*

    */
    private static final long serialVersionUID = 1L; //指定死了 序列化编码
    private int id;
    private String username ;
    private String password ;
    private int age ;
    private Date birth;
    private String sex ;

    // 省略 各种自动生成的方法
    }
    • 当你在写数据的时候 我们的实体有一个序列化的编码 ,但是只要你的实体发生了变化 ,这个序列化的编码就发行变化
    • 当读数据的时候,对象流会检查数据改变前后的 序列化编码是否一致 ,如果不一致 就会报这个错误
  4. 如果在对象中 有一个属性或者 某几个属性 我不想进行序列化存储public class User implements Serializable {
    /*

    */
    private static final long serialVersionUID = 1L;
    private int id;
    private String username ;
    private String password ;
    private transient int age ; // 不想保存到文件
    private Date birth;
    //transient 关键词修饰分属性 不会被序列化
    }