Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/file/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何正确关闭OutputStream?_Java_File_Outputstream - Fatal编程技术网

Java 如何正确关闭OutputStream?

Java 如何正确关闭OutputStream?,java,file,outputstream,Java,File,Outputstream,在下面,您可以找到服务器的构造函数,以便对其进行设置。简而言之,它恢复了上次读取对象列表(称为log)和两个int(称为currentTerm和votedFor)时的状态。每当这些“volatile”字段中的任何一个被更新时,相关文件也必须被更新(从而使其适应一致状态),因此我需要两个名为metadataWriter和logWriter的ObjectOutPutStream。由于服务器随时都可能停机,因此我无法编写任何close()方法。您认为下一次设置服务器时(在读取操作期间),要避免出现EO

在下面,您可以找到服务器的构造函数,以便对其进行设置。简而言之,它恢复了上次读取对象列表(称为
log
)和两个
int
(称为
currentTerm
votedFor
)时的状态。每当这些“volatile”字段中的任何一个被更新时,相关文件也必须被更新(从而使其适应一致状态),因此我需要两个名为
metadataWriter
logWriter
ObjectOutPutStream
。由于服务器随时都可能停机,因此我无法编写任何
close()
方法。您认为下一次设置服务器时(在读取操作期间),要避免出现
EOFEException
异常,唯一可能的解决方案是每次
flush()
输出流(就像我在代码的最后一行所做的那样)

公共服务器RMI(…) { ... log=新的ArrayList(); 试一试{ //如果日志文件存在,那么元数据也应该存在 if(Files.exists(path.get(“服务器”+id+“日志”)、LinkOption.NOFOLLOW_LINKS)) { reader=newobjectinputstream(newfileinputstream(“服务器”+id+“日志”)); 尝试 { while(true) 添加((LogEntry)reader.readObject()); } 捕获(EOFEException e){} catch(classnotfounde异常){ e、 printStackTrace(); } reader=newobjectinputstream(newfileinputstream(“服务器”+id+“元数据”)); currentTerm=reader.readInt(); votedFor=reader.readInt(); } else//如果是第一次设置服务器,请初始化所有持久字段 { 当前项=1; votedFor=-1; log=新的ArrayList(); } logWriter=newobjectoutputstream(newfileoutputstream(“服务器”+id+“日志”)); metadataWriter=新的ObjectOutputStream(新的FileOutputStream(“服务器”+id+“元数据”)); //因为创建一个新的ObjectOutputStream会用一个空文件覆盖旧文件,所以我们首先要重写旧内容 用于(日志条目:日志) logWriter.writeObject(条目); metadataWriter.writeInt(当前术语); metadataWriter.writeInt(votedFor); metadataWriter.flush(); }catch(filenotfounde异常){ e、 printStackTrace(); }捕获(IOE异常){ e、 printStackTrace(); } ... } 重要提示:

我不认为像有人建议的那样,在每个使用资源的方法中尝试(以及更新服务器状态的每个方法)是一个可行的解决方案,因为
元数据
文件是可以的(在每次更新/写入文件时总是替换写入其中的两个
int
)但是对于
log
文件,它意味着每次更改时都要写入整个列表(对它所做的操作不仅是appen,而且是replacement!),我认为这对性能不太好

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();
    }
}

我建议您使用try-with-resource,一次编写整个集合,在出现异常之前无需阅读。您可以在开始时编写元数据

List<LogEntry> entries = ..
try (ObjectOutputStream out = new ObjectOutputStream(....)) {
    out.writeObject(currentTerm);
    out.writeObject(votedeFor);
    out.writeObject(entries);
}
列表条目=。。
try(ObjectOutputStream out=新的ObjectOutputStream(..){
out.writeObject(当前术语);
out.writeObject(votedeFor);
out.writeObject(条目);
}
阅读你能做什么

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();
}
String currentTerm=“无”;
字符串votedFor=“无人”;
列表条目=Collections.emptyList();
try(ObjectInputStream in=新ObjectInputStream(..){
.readObject()中的currentTerm=(字符串);
.readObject()中的votedFor=(字符串);
.readObject()中的条目=(列表);
}
注意:这需要Java7,但考虑到它将是EOL,如果可以的话,我建议升级到Java8

我认为这对性能不太好

这是一个非常不同的问题,但您仍然可以使用try with resource。解决方案是只追加新条目。要做到这一点,你需要

  • ObjectOutputStream之上的一种协议,支持附加到文件。ObjectOutputStream不会为您这样做,相反,您需要编写数据块,并且需要一种将这些数据块粘在一起的方法
  • 一种确定自上次写入磁盘以来发生了哪些更改/添加了哪些内容并仅将更改写入磁盘的方法
在您假设性能不好之前,您应该测试它,因为您可能会发现它不值得为节省几毫秒而增加复杂性

顺便说一句,如果你真的关心性能,不要使用ObjectOutputStream,它是通用的、灵活的,但速度非常慢

因此OutpuStreamObject(是类字段,不是构造函数局部变量)没有正确关闭

在这种情况下,文件将被损坏。您需要一种验证文件和截断无效数据的方法


看看我写的图书馆。它可以解决您的许多问题,因为它支持

  • 多线程、进程或机器的连续写入
  • 如果进程或线程在写入时死亡,则损坏的条目将被截断或忽略
  • 如果进程在两次写入之间死亡,则不会丢失数据
  • 它支持更有效的序列化方法
  • 它可以由多个线程/进程读取
    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();
    }