1

I want to serialize a Hashtable to a file using ObjectOutputStream.writeObject(), but I want the writer to always overwrite any existing object such that only a single object exists:

FileOutputStream fout = new FileOutputStream( f);
ObjectOutputStream writer = new ObjectOutputStream(fout);
writer.writeObject( hashtable);
writer.flush();

The hastable is updated intermittently at runtime, so I use a helper method to persist its state:

private void persistObject( Hashtable ht){
   writer.writeObject( ht);
   writer.flush();
}

The problem is every time I call writeObject(), a new hastable is appended to the file; Is there any way to just overwrite whatever is in the file so only a single object is ever persisted?

4

3 回答 3

8

最简单的方法是关闭并重新打开文件,只需在您的 persistObject() 方法中重新运行此代码:

private void persistObject( Hashtable ht){
    try (ObjectOutputStream writer = new ObjectOutputStream(new FileOutputStream(f))) {
        writer.writeObject( hashtable);
        writer.flush();
        writer.close();
    }
}
于 2013-08-16T02:26:44.407 回答
1

您应该在persistObject 中打开/写入/关闭ObjectOutputStream。您不应该在位置 0 处截断文件。ObjectOuputStream 具有复杂的结构,不仅是对象数据,还有标头、类描述符等。截断会破坏它,在尝试读取它时导致 StreamCorruptedException。

于 2013-08-16T03:56:46.960 回答
1

如果您想丢弃文件内容并重新开始写入文件的开头,您可以获取它的频道并重新定位内容。问题是,ObjectStreams 使用一些内部标头,如果我们想“重置”流,我们需要考虑这一点。

在实例化之后ObjectOutputStream,存储初始位置(writeStreamHeader写入两个短裤 - 消耗 4 个字节,但最好是通用的而不是抱歉),以便您可以定位通道而不覆盖标题。

final long initialPosition = fout.getChannel().position();

然后,每次你必须写东西时,跳过初始字节(通过定位通道),重置流并写你的对象:

//java 1.7
private void persistObject(Hashtable ht){
   fout.getChannel().position(initialPosition);
   fout.reset();
   writer.writeObject(ht);
   writer.flush();
}
//java 1.6
private void persistObject(Hashtable ht){
   fout.getChannel().position(initialPosition);
   fout.getChannel().truncate(initialPosition);
   writer.writeObject(ht);
   writer.flush();
}

正如@bgp 提到的,我不认为打开/关闭文件真的会引入那么多开销......而且我认为每次写入时截断和刷新到磁盘不是有效的,或者长时间保持文件流打开一段时间是一种很好的做法(或安全),但破解ObjectOutputStream.

于 2013-08-16T02:33:29.720 回答