下面你会找到服务器的构造函数来设置它。简而言之,它从上次读取List
个对象(称为log
)和两个int
(称为currentTerm
和{ {1}})。任何时候任何这些“易变”字段都会被更新,相关文件也必须更新(因此要更新一致状态),所以我需要两个votedFor
调用ObjectOutPutStream
和metadataWriter
。由于服务器可能随时 ,我无法编写任何logWriter
方法。您认为下次我设置服务器时(在读取操作期间)避免close()
的唯一可能解决方案是每次EOFException
输出流(就像我已经完成的那样)代码的最后几行)?
flush()
重要提示:
我不认为使用它们的每个方法中的try-with-resources (以及更新服务器状态的每个方法)都是一个可行的解决方案,因为它会好的 public ServerRMI(...)
{
...
log = new ArrayList<>();
try {
//if Log file exists then should exists Metadata too
if(Files.exists(Paths.get("Server" + id + "Log"), LinkOption.NOFOLLOW_LINKS))
{
reader = new ObjectInputStream(new FileInputStream("Server"+id+"Log"));
try
{
while(true)
log.add((LogEntry) reader.readObject());
}
catch (EOFException e){}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
reader = new ObjectInputStream(new FileInputStream("Server"+id+"Metadata"));
currentTerm = reader.readInt();
votedFor = reader.readInt();
}
else//if it is the first time that the server is set up initialize all persistent fields
{
currentTerm = 1;
votedFor = -1;
log = new ArrayList<LogEntry>();
}
logWriter = new ObjectOutputStream(new FileOutputStream("Server"+id+"Log"));
metadataWriter = new ObjectOutputStream(new FileOutputStream("Server" + id + "Metadata"));
//since creating a new ObjectOutputStream overwrite the old file with the an empty one, as first thing we rewrite the old content
for(LogEntry entry : log)
logWriter.writeObject(entry);
metadataWriter.writeInt(currentTerm);
metadataWriter.writeInt(votedFor);
metadataWriter.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
...
}
文件(写在其上的两个metadata
总是在每次更新/写入文件时被替换)但是对于int
文件,它意味着每个都写入整个列表它被改变的时间(在它上面进行的操作不仅是appen,而且也是替换!),我认为它对性能不太好!
答案 0 :(得分:2)
我建议您使用try-with-resource并立即编写整个集合,并且在获得异常之前不必阅读。您可以在开始时编写元数据。
List<LogEntry> entries = ..
try (ObjectOutputStream out = new ObjectOutputStream(....)) {
out.writeObject(currentTerm);
out.writeObject(votedeFor);
out.writeObject(entries);
}
阅读你可以做到
String currentTerm = "none";
String votedFor = "no-one";
List<LogEntry> entries = Collections.emptyList();
try (ObjectInputStream in = new ObjectInputStream(....)) {
currentTerm = (String) in.readObject();
votedFor = (String) in.readObject();
entries = (List<LogEntry>) in.readObject();
}
注意:这需要Java 7,但鉴于它即将成为EOL,如果可以,我建议升级到Java 8.
我认为它对表现不太好!
这是一个非常不同的问题,但你仍然会使用try-with-resource。解决方案是仅添加新条目。要做到这一点,你需要,
Befor eyou假设性能不好,你应该测试它,因为你可能会发现不值得增加复杂性来节省几毫秒。
顺便说一句,如果你真的关心性能,不要使用ObjectOutputStream,它通用且灵活,但速度很慢。
所以OutpuStreamObject(它是类字段,而不是构造函数局部变量)未正确关闭。
在这种情况下,文件将被破坏。您需要一种验证文件并截断无效数据的方法。
看一下我写的图书馆。 Chronicle Queue它可以解决您支持的许多问题
答案 1 :(得分:1)
The try-with-resources Statement
try-with-resources语句是一个声明一个或多个资源的try语句。资源是在程序完成后必须关闭的对象。 try-with-resources语句确保在语句结束时关闭每个资源。
实施例
static String readFirstLineFromFile(String path) throws IOException {
try (BufferedReader br =
new BufferedReader(new FileReader(path))) {
return br.readLine();
}
}