Java中对象的序列化和反序列化操作
Java的IO流不仅可以对字符进行传输,也可以对对象进行传输,叫做对象的序列化和反序列化
序列化:将对象转为方便传输的流(对象写入文件)
反序列化:将流转换成对应的对象(把对象从文件中拿出)
注意:如果我们需要将对象序列化到文件,首先需要让需要序列化对象对应的类实现序列化接口Serializable,该接口中没有任何方法和属性,仅仅只是一个标志,表示实现该接口的类是可以被序列化的;如果没有实现该接口就进行序列化,会报出NotSerializableException没有序列化的异常
import java.io.Serializable;
public class User implements Serializable {
/**
* 用户名
*/
String userName;
/**
* 密码
*/
String password;
public User() {
}
public User(String deliverUserName,String deliverPassword) {
userName = deliverUserName;
password = deliverPassword;
}
@Override
public String toString() {
return "User [userName=" + userName + ", password=" + password + "]";
}
}
1.对象进行序列化和反序列化
序列化和反序列化
类名 | 方法名 | 作用 | |
---|---|---|---|
序列化 | ObjectOutputStream | void write(Object obj) | 将指定的对象序列化到流中 |
反序列化 | ObjectInputStream | Object readObject() | 将流反序列化为对象并返回 |
序列化
序列化使用的是对象的输出流ObjectOutputStream(OutputStream out),使用时,传递的是一个字节输出流
//创建对象序列化的对象
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream("src/com/test/ser/user.txt",true));
}catch (IOException e) {
e.printStackTrace();
}finally {
//释放资源
if(oos!=null) {
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
成功创建对象的输出流后,我们就需要创建对象,然后吧对象进行序列化了
//创建对象序列化的对象
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream("src/com/test/ser/user.txt",true));
//创建User的对象
User user = new User("java","123456");
//讲user序列化到文件中
oos.writeObject(user);
System.out.println("序列化成功");
}catch (IOException e) {
e.printStackTrace();
}finally {
//释放资源
if(oos!=null) {
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
序列化成功后,就可以在文件中看到我们序列化后的对象了
注意:序列化的时候会写进一个头标,这头标就是定位的,当我们反序列化的时候,会从这个头标开始读取;每次序列化对象都会写入一个头标,当我们反序列化读取多个对象的时候就会报出StreamCorruptedException: invalid type code: AC的异常
为什么会这样呢?
因为序列化的时候都会调用writeStreamHeader()方法,该方法就是用于写头标的,每次序列化都会调用该方法
为了避免写入多个头标,所以我们可以实现他的一个子类,然后空实现这个方法来防止多个头标的出现
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
public class Sub extends ObjectOutputStream {
public Sub(OutputStream out) throws IOException {
super(out);
}
@Override
protected void writeStreamHeader() throws IOException {
}
}
空实现这个方法后,我们使用的时候,如果文件是空的时候就创建父类的对象,如果文件不为空的时候就可以创建子类的对象来防止出现多个头标
//创建对象序列化的对象
ObjectOutputStream oos = null;
try {
//创建文件类封装文件路径
File file = new File("src/com/test/ser/user.txt");
//判断是否为空
if(file.length()<1) {
oos = new ObjectOutputStream(new FileOutputStream(file,true));
}else {
oos = new Sub(new FileOutputStream(file,true));
}
//创建User的对象
User user = new User("java","123456");
//讲user序列化到文件中
oos.writeObject(user);
System.out.println("序列化成功");
}catch (IOException e) {
e.printStackTrace();
}finally {
//释放资源
if(oos!=null) {
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
通过一个File类中length()方法进行判断就可以根据需要进行不同对象的创建,防止了多个头标出现而导致的异常
反序列化
反序列化使用的是ObjectInputStream(InputStream in),使用时需要我们传递的是一个字节输入流
//创建反序列化的对象
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream("src/com/test/ser/user.txt"));
} catch (IOException e) {
e.printStackTrace();
}finally {
//释放流
if(ois!=null) {
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
创建对象后就可以去指定文件拿取对象了
// 创建反序列化的对象
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream("src/com/test/ser/user.txt"));
// 用于接收的对象
Object obj = null;
// 开始读取
while ((obj = ois.readObject()) != null) {
User user = (User) obj;
System.out.println(user.toString());
}
/*
* 打印结果:
* User [userName=java, password=123456]
* java.io.EOFException
* atjava.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2917)
* atjava.io.ObjectInputStream.readObject0(ObjectInputStream.java:1502)
* atjava.io.ObjectInputStream.readObject(ObjectInputStream.java:422)
* atcom.test.ser.UserDeserializableTest.main(UserDeserializableTest.java:16)
*/
} catch (Exception e) {
e.printStackTrace();
} finally {
// 释放流
if (ois != null) {
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
通过打印结果可以看到报出了EOFException异常,这个异常表示的是,读取用的指针已经到达末尾了,所以可以多一个catch来异常解决即可
// 创建反序列化的对象
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream("src/com/test/ser/user.txt"));
// 用于接收的对象
Object obj = null;
// 开始读取
while ((obj = ois.readObject()) != null) {
User user = (User) obj;
System.out.println(user.toString());
}
/*
* 打印结果:
* User [userName=java, password=123456]
* 读取完毕
*/
} catch(EOFException e) {
System.out.println("读取完毕");
} catch (Exception e) {
e.printStackTrace();
} finally {
// 释放流
if (ois != null) {
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
这样我们就可以通过反序列化拿到文件中的对象了
今天的分享就到这里了,欢迎大家来一起交流学习!
本文地址:https://blog.csdn.net/m0_48008264/article/details/107358660
下一篇: PlayJava Day016
推荐阅读
-
Java中对象的序列化和反序列化操作
-
定义两个接口,其中各包括一个抽象方法分别用来完成两个数的加法和减法操作,然后创建一个类KY6_3来实现这两个接口中的抽象方法。编写程序KY6_3.java,将源程序写在实验报告中。
-
Java8中 LocalDate和java.sql.Date的相互转换操作
-
PHP中的串行化变量和序列化对象_php基础
-
Java 中的日期和时间操作
-
JAVA中的日期和时间 操作汇总
-
PHP中的串行化变量和序列化对象
-
PHP中的串行化变量和序列化对象_PHP
-
python中内置函数和json、pickle的数据序列化代码实例
-
PHP中SERIALIZE和JSON序列化与反序列化的区别