欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

java.io.StreamCorruptedException解决方案

程序员文章站 2022-04-03 19:52:59
...

序列化和反序列化的过程中,我们会用到ObjectOutputStream和ObjectInputStream

ObjectOutputStream用于将对象系列化,它可以把一个对象用二进制的方式表示,可以把一个对象通过ObjectInputStream进行还原。这在网络环境下是非常有用的。可以把一个object通过二进制流在网络上进行传播。

 

通过代码说话吧:

ObjectOutputStream objput=null;

File outTo=new File("D:/students.dat");

FileOutputStream fileout=new FileOutputStream(outTo,true);

objput=new ObjectOutputStream(fileout);

Student ms=new Student(12345,'男',21,"明帅","软件工程");

objput.writeObject(ms);

objput.writeObject(ms);

objput.flush();

‍‍‍这段代码把对象序列化后存放在文件中,前面的一篇文章我详细讨论了系列化算法,系列化算法首先会在文件中写入一些头部信息,声明使用了序列化协议和使用系列化的版本,如下图所示,黄色部分代表写入的对象。

‍‍‍

‍‍‍‍‍‍‍‍‍‍再进行反序列化时,这没有任何问题。

但注意上面的这段代码:FileOutputStream(outTo,true);

True表示可以在文件后面追加信息,当再次调用这段代码时,会打开一个新的流,在写入时头部信息重新会输入一遍。写入后如下所示:

‍‍‍‍
‍‍‍这时再进行反序列化操作,后面的那个头就无法识别,会终止反序列化,并抛出java.io.StreamCorruptedException

异常。通常情况下不可能一次把所有的对象通过一个流一次性写入文件,不可避免的会出现上面的问题,所以解决这个问题就很有必要。

 

解决这个问题需要重写一个类,让它继承ObjectOutputStream类,并覆写其中的writeStreamHeader方法。这个方法定义如下:

writeStreamHeader

protected void writeStreamHeader()

                           throws IOException

提供 writeStreamHeader 方法,这样子类可以将其自身的头部添加或预加到流中。它可以将幻数 (magic number) 和版本写入流。

这个方法可以自定义流的头部,也就上面图中的黄色部分。

 

还要用到另外的一个函数reset(),其定义如下:

reset

public void reset()

            throws IOException

重置将丢弃已写入流中的所有对象的状态。重新设置状态,使其与新的 ObjectOutputStream 相同。将流中的当前点标记为 reset,相应的 ObjectInputStream 也将在这一点重置。以前写入流中的对象不再被视为正位于流中。它们会再次被写入流。

用上面的那两个方法,我们可以对ObjectOutputStream 进行一下改造:

public class ReuseObjectOutputStream extends ObjectOutputStream{

 

public ReuseObjectOutputStream(OutputStream arg0) throws IOException {

super(arg0);

// TODO Auto-generated constructor stub

}

 

public void writeStreamHeader(){

try {

this.reset();

} catch (IOException e) {

// TODO Auto-generated catch block

System.out.println("流重置出现问题....");

}

}

}

writeStreamHeader方法被ObjectOutputStream对象在写入具体的数据时自动调用。Reset()方法把流之前写入的所有信息都抹掉,相当于进行如下图A到图B的转换,这样序列化后就没有任何问题。

 

 

‍‍

具体使用的时候要注意一点,因为头部信息是必不可少的,否则无法被反系列化,当上述逻辑中,当文件中没有任何信息的时候,必须用到一个普通的ObjectOutputStream进行数据的写入。以后的再次写入时用ReuseObjectOutputStream对象进入系列化。

 

转自:http://hi.baidu.com/xiyandada/item/dee3a4e79c0fb91a585dd8ee