Java writeObject()总是覆盖现有对象,永远不会追加?

时间:2013-08-16 02:23:06

标签: java object file-io

我想使用ObjectOutputStream.writeObject()将Hashtable序列化为文件,但我希望编写器始终覆盖任何现有对象,以便只存在单个对象:

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

hastable在运行时间歇性更新,因此我使用辅助方法来保持其状态:

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

问题是每次我调用writeObject()时,都会在文件中附加一个新的hastable;有没有办法只覆盖文件中的任何内容,因此只保留一个对象?

3 个答案:

答案 0 :(得分:8)

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

private void persistObject( Hashtable ht){
    try (ObjectOutputStream writer = new ObjectOutputStream(new FileOutputStream(f))) {
        writer.writeObject( hashtable);
        writer.flush();
        writer.close();
    }
}

答案 1 :(得分: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

答案 2 :(得分:1)

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