序列化在Java中,从文件中完全读取对象流的最佳方法是什么?
我正在创建一个可能很长的对象日志,不想在写入文件之前将它们全部保存在内存中,因此无法将对象的序列化集合写入文件。我试图在完成日志记录后,找出读取整个对象流的“最佳”方式
我注意到以下情况不起作用:
FileInputStream fis = new FileInputStream(log);
ObjectInputStream in = new ObjectInputStream(fis);
while ((obj = in.readObject()) != null) {
// do stuff with obj
}
因为流在到达文件末尾时抛出异常,而不是返回null(可能是因为可以向对象流写入/读取null,从而导致上述循环的行为不符合预期)
有没有比以下更好的方法来完成我想通过上述循环完成的事情:
FileInputStream fis = new FileInputStream(log);
ObjectInputStream in = new ObjectInputStream(fis);
try {
while (true) {
obj = in.readObject();
// do stuff with obj
}
} catch (EOFException e) {
}
这似乎有点笨拙。对于文件结束对象解决方案,以下是最佳方法吗
private static final class EOFObject implements Serializable {
private static final long serialVersionUID = 1L;
}
void foo() {
Object obj;
while (!((obj = in.readObject()) instanceof EOFObject)) {
BidRequest bidRequest = ((BidRequestWrapper) obj).getBidRequest();
bidRequestList.add(bidRequest);
}
}
# 1 楼答案
你的代码不正确。readObject()在EOS时不返回null,它抛出EOFEException。所以抓住它。如果写入了Null,则返回Null。您不需要上面建议的所有布尔或标记对象
# 2 楼答案
使用Java序列化时不满足此要求,因为序列化流维护对以前编写的对象的强引用,大概是为了在这些对象需要再次序列化时写回引用。这可以通过运行以下命令进行验证:
反序列化文件时也存在类似的问题。要解析回引用,流很可能会使所有以前读取的对象保持活动状态,以解析序列化流中对这些对象的潜在回引用
如果您确实需要能够在流完全写入之前释放这些对象,那么您可能希望为每个(一批)对象使用一个新的ObjectOutputStream
ObjectOutputStream.reset()
-当然会失去解析早期流的反向引用的能力。也就是说,以下程序不会抛出OutOfMemoryError:请注意,每次重置后,有关被序列化的类的元数据将被重新写入,这是非常浪费的(上面的程序每整数写入大约80字节…),所以你不应该经常重置,也许每100个对象重置一次
对于检测流的结尾,我发现波佐关于EOF对象的建议是最好的
# 3 楼答案
在每个对象后面写一个
boolean
,最后一个对象后面跟一个false
。所以,在你写出来的流中:然后,当读回它们时,检查标志(您知道每个对象后面总是有一个标志)以决定是否读入另一个标志
boolean
将以非常紧凑的方式存储在序列化流中,因此不会增加太多文件大小# 4 楼答案
你的解决方案似乎很好。只要确保有一个
finally
子句,在那里关闭流或者,您可以创建自己的EOF对象,并将其添加到末尾。因此,您可以检查当前读取的对象是否为
EofObject
,以及此时的break