5

我正在使用 ObjectOutputStream 创建序列化对象的文件。然后,我使用 ObjectInputStream 和 readObject() 方法将对象从文件中取出。

第一次效果很好。这意味着如果文件不存在并且我打开它然后附加任意数量的对象,我可以打开 ObjectInputStream 对象并访问所有对象。

但是,如果我随后打开同一个文件(使用 append 选项)并添加更多对象,ObjectInputStream 对象会收到 java.io.StreamCorruptedException: "invalid type code: AC" 错误,新对象应该从哪里开始。

有没有其他人遇到过这个?我什至回到了 Deitel 书中的一些基本教科书示例,但仍然遇到同样的错误。

编辑:我发现了这一点 - 一旦序列化流关闭并以附加模式重新打开,您可能无法附加到序列化流的末尾。写入似乎可以工作,但是当您稍后再读取文件时,您将收到 java.io.StreamCorruptedException。在“ http://mindprod.com/jgloss/gotchas.html#SERIALIZATION

4

3 回答 3

4

每个对象都作为对象流的一部分进行序列化,而不是作为个体。像大多数文件格式(但不是 ZIP!)一样,“对象流序列化协议”有一个标题。这是每个新人都ObjectInputStream希望仅在文件开头找到的内容。把它放在流的中间是行不通的。流也有反向引用,所以没有对象被写出两次(除非另有说明)。

所以你需要做的是创建一个新ObjectInputStream的来匹配每个ObjectOutputStream. 有一些内部缓冲,如果这会导致问题,您需要先对流进行切片,然后再Object(In|Out)putStream进行处理。

于 2009-06-10T20:17:43.887 回答
1

ObjectStream 包含页眉和页脚。它还包含有状态信息,即它所写的内容是基于它已经写入的对象。

因此,您不能只附加到现有的 ObjectStream。您可以做的是每次重写文件并添加对象,或者使用您自己的协议包装流,以便您可以正确写入/读取多个流。

当您使用相同的代码库(尤其是读/写的类)读/写数据时,ObjectStream 效果最好。ObjectStream 并非旨在跨代码版本或在不同应用程序之间移植。

于 2009-06-11T20:31:18.410 回答
1

如果流的生产者和消费者是独立的,那么每次只覆盖输出文件并添加时间戳文件以便消费者知道重新加载的时间是有意义的。

例如,

SomeObject[] obj = new SomeObject[numObjects];
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("file");
out.writeObject(obj);
out.close();
long ts = System.currentTimeMillis();
ObjectOutputStream tout =
        new ObjectOutputStream(new FileOutputStream("timestamp.obj");
tout.writeObject(new Long(ts));

然后,消费者可以每隔几分钟轮询 timestamp.obj 文件,如果它已更改,SomeObject[]请从流中重新打开。

ObjectInputStream in =
        new ObjectInputStream(new FileInputStream("timestamp.obj"));
Long ts = (Long)in.readObject();

if (ts > prevts) {
    ObjectInputStream in2 = new ObjectInputStream(new FileInputStream("file"));
    SomeObject[] obj = (SomeObject[])in.readObject(); 
    prevts = ts;
}
于 2009-06-10T23:19:04.880 回答