关于java对象的反序列化时产生的异常补充:java.io.StreamCorruptedException: invalid type code: AC(转载)

关于java对象的反序列化时产生的异常补充:java.io.StreamCorruptedException: invalid type code: AC
大家好,我是一位在java学习圈中不愿意透露姓名并苟且偷生的小学员,如果文章有错误之处,还望海涵,欢迎多多指正

问题描述:
// 在向一个文件写入可序列化对象时,每次在文件的末尾添加一个或多个可序列化的对象,
// 于是使用了FileOutputStream(文件名,true)间接的构建了ObjectOutputStream流对象

原因:
// 在一个文件都有一个文件的头部和文件体。由于对多次使用FileOutputStream(文件名,true)
// 构建的ObjectOutputStream对象向同一个文件写数据,
// 在每次写数据的时候他都会向这个文件末尾先写入header在写入你要写的对象数据,
// 在读取的时候遇到这个在文件体中的header就会报错。导致读出时,出现StreamCorrupted异常

特别注意:
//异常产生代码(程序执行时系统会自动添加header,即执行一次文件尾添加一个header)注意上面说的 “一次” 指的是执行一次运行过程,即java.exe
//由于用FileInputStream(文件名,true)向同一个文件中序列化对象,
//每“次”都会向文件中序列化一个header。在反序列化的时候每个
//ObjectInputStream 对象只会读取一个header,那么当遇到第二个的时候就会报错,导致出现异常

具体对象类的描述代码如下:
package io;

import java.io.Serializable;

public class ObjectPerson implements Serializable {
private static final long serialVersionUID = 2017019123524660527L;
private String name;
private String age;

public ObjectPerson(){}
public ObjectPerson(String name,String age){
    this.name = name;
    this.age = age;
}
public String getName(){
    return this.name;
}
public String getAge(){
    return this.age;
}
public String toString(){
    return "{"+this.name+","+this.age+"}";
}

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
解决方法一 通过将对象添加入集合中,从文件中读出集合后再解析集合内容即可(此处样例采用HashSet,小伙伴们想用其他集合也可以根据你的对象内容来判断即可)
ObjectOutputStream oos = null;
try {
HashSet hashSet = new HashSet();
hashSet.add(new ObjectPerson(“我”,“18”));
hashSet.add(new ObjectPerson(“学习”,“20”));
File file = new File(“E://test//Person.txt”);
FileOutputStream fos = new FileOutputStream(file);
oos = new ObjectOutputStream(fos);
oos.writeObject(hashSet);
oos.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(oos != null) {
oos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
//不能直接将新添加的对象直接添加入文件内,
//每次添加都需先从文件读取出来,增加完后再全部重新输入到文件,感觉效率太低!
ObjectInputStream ois = null;
try {
FileInputStream fis = new FileInputStream(new File(“E://test//Person.txt”));
ois = new ObjectInputStream(fis);
HashSet set= (HashSet)ois.readObject();
Iterator i = set.iterator();
while(i.hasNext()){
ObjectPerson op = i.next();
System.out.println(op);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if(ois != null) {
ois.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
解决方法二 重写ObjectOutputStream的writeStreamHeader()方法:
以下是自定义流类重写方法的具体实现代码:
//自己创建一个流的类 继承ObjectOutputStream实现方法重写,当不需要header时即文件长度(即file.length()) < 1 时创建自己定义的这个流类即可
package io;

import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;

public class MyObjectOutputStream extends ObjectOutputStream {
public MyObjectOutputStream(OutputStream out) throws IOException {
super(out);
}
public MyObjectOutputStream() throws IOException, SecurityException {
super();
}

@Override
protected void writeStreamHeader() throws IOException{
    return;
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
以下是方法二具体实现代码:
// 判断是不是第一次写入,若是则写入头部,若不是则不写入头部
1
ObjectOutputStream out = null;
ObjectInputStream in = null;
List list = new ArrayList();
list.add(new ObjectPerson(“我”, “18”));
list.add(new ObjectPerson(“学习”, “20”));
String path = “E://test//Person.txt”;
try { //判断文件大小并调用不同的方法
File file = new File(path);
FileOutputStream fos = new FileOutputStream(file,true);
if (file.length() < 1) {
out = new ObjectOutputStream(fos);
} else {
out = new MyObjectOutputStream(fos);
}
//添加对象
for (int i = 0; i < list.size(); i++) {
out.writeObject(list.get(i));
}
out.flush();
} catch (Exception ex) {
ex.printStackTrace();
} finally {
try {
if(out != null) { //若流通道创建成功,保证流通道必定会被关闭
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
in = new ObjectInputStream(new BufferedInputStream(new FileInputStream(path)));
while (true) {
//EOFException说明读不到对象了
ObjectPerson op = (ObjectPerson) in.readObject();
System.out.println(op);
}
} catch (EOFException e) {
//可以跟我一样做个提示而不用抛出异常
System.out.println(“读取完毕”);
} catch (Exception ex) {
ex.printStackTrace();
}try {
if(in != null) { //若流通道创建成功,保证流通道必定会被关闭
in.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
解决方法三 在反序列化的过程中,每次都创建一个新的ObjectInputStream用来读取header,本次样例对象数据较少故未用集合做每次添加个数的记录,有兴趣的小伙伴可以自己尝试一下哦
// 我们先看看用while循环可能会产生的漏洞
1
ObjectOutputStream oos = null;
try {
FileOutputStream fos = new FileOutputStream(new File(“E://test//Person.txt”),true);
oos = new ObjectOutputStream(fos);
oos.writeObject(new ObjectPerson(“我”, “18”));
oos.writeObject(new ObjectPerson(“学习”, “100”));
oos.writeObject(new ObjectPerson(“世界”, “1000000”));
oos.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if(oos != null) {
oos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
ObjectInputStream ois = null;
try {
FileInputStream fis = new FileInputStream(new File(“E://test//Person.txt”));
while(fis.available() > 0) {
ois = new ObjectInputStream(fis);
ObjectPerson op = (ObjectPerson)ois.readObject();
System.out.println(op);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if(ois != null) {
ois.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
上面代码运行后结果为:
// {我,18}
// java.io.StreamCorruptedException: invalid stream header: 7371007E
那么为什么会出现这个异常呢,其实每一个ois对象都会只读一个header,如果没读到或者读多了就凉了,不妨细细看看文章刚开始对此header的描述吧,一脸奸笑嘿嘿(伏笔成功)
1
2
3
接下来我们看正确解决方法:
ObjectOutputStream oos = null;
try {
FileOutputStream fos = new FileOutputStream(new File(“E://test//Person.txt”),true);
oos = new ObjectOutputStream(fos);
//第一次执行添加三个对象
oos.writeObject(new ObjectPerson(“我”, “18”));
oos.writeObject(new ObjectPerson(“学习”, “100”));
oos.writeObject(new ObjectPerson(“世界”, “1000000”));
//第二次执行添加两个对象
// oos.writeObject(new ObjectPerson(“你”, “20”));
// oos.writeObject(new ObjectPerson(“他”, “21”));
oos.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if(oos != null) {
oos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
ObjectInputStream ois = null;
try {
FileInputStream fis = new FileInputStream(new File(“E://test//Person.txt”));
//第一个ois读第一次添加的三个对象
ois = new ObjectInputStream(fis);
ObjectPerson op1 = (ObjectPerson)ois.readObject();
System.out.println(op1);
ObjectPerson op2 = (ObjectPerson)ois.readObject();
System.out.println(op2);
ObjectPerson op3 = (ObjectPerson)ois.readObject();
System.out.println(op3);
//第二个ois读第二次添加的两个对象
// ois = new ObjectInputStream(fis);
// ObjectPerson op4 = (ObjectPerson)ois.readObject();
// System.out.println(op4);
// ObjectPerson op5 = (ObjectPerson)ois.readObject();
// System.out.println(op5);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if(ois != null) {
ois.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}

看到此处是不是感觉豁然开朗呢,但是此方法实际操作大量对象数据时很耗空间,比如每次添加2个,那么每2个就要记录一次(根据每次添加的对象个数不同而不同),可以记录在集合中(因为集合长度可变),拿ArrayList举例,此时每一个索引对应的数据都是2,所以每读2个就要创建一个新的ois

原文链接:https://blog.csdn.net/bw_cx_fd_sz/article/details/107406096?utm_medium=distribute.pc_feed.none-task-blog-personrec_tag-9.nonecase&depth_1-utm_source=distribute.pc_feed.none-task-blog-personrec_tag-9.nonecase&request_id=5f1fef4a9cc79f6252ce3b00

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值