ObjectOutputStream向文件尾追加对象的问题

1.下面是一段测试程序

 

<span style="white-space:pre">		</span>//创建一个Record对象
		Integer integ2 = new Integer(1);
		Record record2 = new Record();
		record2.fields.add(integ2);

		//创建一个Record对象
		Integer integ3 = new Integer(2);
		Record record3 = new Record();
		record3.fields.add(integ3);

		//将对象record2写入到文件
		FileOutputStream fo = new FileOutputStream("redo2.log", true);
		ObjectOutputStream so = new ObjectOutputStream(fo);
		so.writeObject(record2);
		so.close();
		fo.close();

		//将对象record3追加到文件
		FileOutputStream fo1 = new FileOutputStream("redo2.log", true);
		ObjectOutputStream so1 = new ObjectOutputStream(fo1);
		so1.writeObject(record3);
		so1.close();
		fo1.close();

		//创建一个输入流
		FileInputStream fi = new FileInputStream("redo2.log");
		ObjectInputStream ois = new ObjectInputStream(fi);
		
		//读取一个对象
		Record record21 = (Record) ois.readObject();
		System.out.println(record21.fields);

		//读取一个对象
		Record record31 = (Record) ois.readObject();
		System.out.println(record31.fields);

执行上边的测试程序,控制台会输出下面的内容:

[1]
Exception in thread "main" java.io.StreamCorruptedException: invalid type code: AC
	at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1377)
	at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370)
	at com.highgo.hgdbadmin.log.Log.main(Log.java:143)


出错的代码是下面这行开始:

Record record31 = (Record) ois.readObject();


2.原因

看下面的两段代码

public ObjectOutputStream(OutputStream out) throws IOException {
        verifySubclass();
        bout = new BlockDataOutputStream(out);
        handles = new HandleTable(10, (float) 3.00);
        subs = new ReplaceTable(10, (float) 3.00);
        enableOverride = false;
        writeStreamHeader();
        bout.setBlockDataMode(true);
        if (extendedDebugInfo) {
            debugInfoStack = new DebugTraceInfoStack();
        } else {
            debugInfoStack = null;
        }
    }

public ObjectInputStream(InputStream in) throws IOException {
        verifySubclass();
        bin = new BlockDataInputStream(in);
        handles = new HandleTable(10);
        vlist = new ValidationList();
        enableOverride = false;
        readStreamHeader();
        bin.setBlockDataMode(true);
    }


这两个分别是ObjectOutputStream和ObjectInputStream的构造方法。可以看到,代码非常对称。其中有两个方法ObjectOutputStream#writeStreamHeader和ObjectInputStream#readStreamHeader已经牵扯到修改文件和读文件了。这时我们可以发现,在测试代码中,我们new了两个ObjectOutputStream对象,也就是说,我们往文件中写了两次StreamHeader,而我们只new了一个ObjectInputStream对象,也就是说,只读一次StreamHeader,这样在读了第一个对象之后,之后的要读的内容和写的内容就不对称了。具体可以看下面这个图,图中上边的是测试代码实际写入的内容,下面的是测试代码想要读出的内容,可以看到,只有第一个对象对上号了,第二个对象没有对上号。

这里我们可以看下StreamHeader的内容:

protected void writeStreamHeader() throws IOException {
        bout.writeShort(STREAM_MAGIC);
        bout.writeShort(STREAM_VERSION);
    }

很简单,一个魔数,一个版本号。两个都是short类型,占4个字节。

3.解决方法

在了解了上边的原理之后,解决的方式就多种多样了,只要让写入的内容和预期的读的内容对上号就行了。下面举个例子:

比如,可以看上边的图片,我们只要不写入StreamHeader不就可以了,这样分别继承ObjectOutputStream和ObjectInputStream,分别重写writeStreamHeader和readStreamHeader方法,让他们doNothing就Okay了。具体实现如下:

public class MyObjectOutputStream extends ObjectOutputStream {

	public MyObjectOutputStream(OutputStream os) throws IOException, SecurityException {
		super(os);
	}

	@Override
	protected void writeStreamHeader() throws IOException {
		super.reset();
	}
}

public class MyObjectInputStream extends ObjectInputStream{

	public MyObjectInputStream(InputStream in) throws IOException {
		super(in);
	}

	@Override
	protected void readStreamHeader() throws IOException, StreamCorruptedException {
	}
}

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈振阳

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值