【发布时间】:2011-02-13 12:08:54
【问题描述】:
如果我只是在输出流中调用close(),输出是有保证的,还是需要我一直调用flush()?
【问题讨论】:
-
你应该接受@TomHawtin的answer
如果我只是在输出流中调用close(),输出是有保证的,还是需要我一直调用flush()?
【问题讨论】:
虽然close 应该调用flush,但它比这要复杂一些...
首先,装饰器(如BufferedOutputStream)在Java 中很常见。装饰器的构造可能会失败,因此您需要 finally 块中的“原始”流 close try 包含装饰器。在出现异常的情况下,您通常不需要 close 装饰器(例如,压缩装饰器实现不佳的情况除外)。在非异常情况下,您通常需要 flush 装饰器。因此:
final RawOutputStream rawOut = new RawOutputStream(rawThing);
try {
final DecoratedOutputStream out = new DecoratedOutputStream(rawOut);
// ... stuff with out within ...
out.flush();
} finally {
rawOut.close();
}
最重要的是,装饰器close 方法经常被错误地实现。这包括直到最近在java.io 中的一些内容。
当然,您可能想使用 Execute Around 习语来保持 DRY(ish)。
编辑: 从 Java 8 开始,您可以使用 try-with-resource 语句,该语句应该可以简洁明了地处理所有内容。即使不必要,代码也会对每个资源调用 close。
try (
RawOutputStream rawOut = new RawOutputStream(rawThing);
DecoratedOutputStream out = new DecoratedOutputStream(rawOut)
) {
// ... stuff with out within ...
}
【讨论】:
final RawOutputStream rawOut = new RawOutputStream(rawThing); Closeable resource = res; try { res = new DecoratedOutputStream(rawOut); /* etc */ res.flush(); } finally { res.close(); }。作为一种模式可能会引起人们的兴趣
close 会导致代码过于复杂,并且通常会出现特殊的错误。 Java I/O 库的设计非常糟糕,例如在装饰器上有close,不幸的是,Java SE 8 Stream 的设计更糟糕。 Execute Around 习惯用法可以防止这种混乱的重复(每个资源执行一次),并且不再那么冗长了。
Close() 总是刷新所以不需要调用。
编辑:这个答案基于常识和我遇到的所有输出流。谁将在不先刷新缓冲区的情况下为缓冲流实现 close() ?在 close() 之前调用 flush 是没有害处的。但是,如果过度调用 flush() 会产生后果。它可能会在缓冲机制下失效。
【讨论】:
FilterOutputStream.close()。
这里有很多危险的答案和cmets。继续阅读我为什么使用危险这个词。
首先要做的事情。看看这些。
您会发现,没有任何一条语句说close() 会调用flush()。如果我错过了,请修复我。
当您需要或需要保证缓冲数据至少刷新到操作系统级别时,请使用flush()。
flush() 有自己的用途。
// client
// sends exactly 234 bytes
// and returns exactly 124 bytes from the server
static byte[] sendAndReceive(final OutputStream output,
final InputStream input)
throws IOException {
final byte[] request = new byte[234];
output.write(request);
// output.flush(); // @@? is this required or not?
final byte[] response = new byte[124];
new DataInputStream(input).readFully(response);
return response;
}
// server
// recieve exactly 234 bytes from the client
// sends exactly 124 bytes
static void receiveAndSend(final InputStream input,
final OutputStream output)
throws IOException {
final byte[] request = new byte[234];
new DataInputStream(input).readFully(request);
final byte[] response = new byte[124];
output.write(response);
// output.flush(); // @@? is this required or not?
}
事情可能已经改变,但我在大约十年前亲身体验过。上面的源代码(客户端)在 Windows XP 上运行,但在 Windows 2000 Server 上运行失败,用于同一端点(服务器)。
并且(您)不必(必须)依赖close() 的任何实现特定行为。
static void writeFile(File file, byte[] bytes) throws IOException {
try (OutputStream out = new FileOutputStream(bytes)) {
out.write(bytes);
out.flush(); // who cares what FileInputStream#close does?
}
}
另外请注意,flush() 并不意味着将数据写入/发送到物理磁盘或远程端点。大多数情况下,它只是将 JVM 中的缓冲数据刷新到底层操作系统中。
勘误表
Writer#close() 明确表示它
关闭流,先刷新它。
但这并不意味着所有子类都保持这个根契约。参见PrintWriter#close(),它(没有flush())关闭了内部out(Writer),这又取决于out的close()实现。
【讨论】:
FileOutputStream 将写入所有写入数据?
FileOutputStream 实现都不应覆盖flush 并且不应缓冲。
FilterOutputStream.close(),并注意BufferedOutputStream 扩展了它。黑天鹅谬误。你只寻找白天鹅。
如果你想刷新流,那么是,在调用close()之前调用flush()。
尽管所有其他答案都相反(但正如在某些 cmets 中正确指出的那样),java.io.OutputStream::close() 的默认实现 不 调用 flush()。事实上,它什么也没做。如果您有源代码分发,您可以轻松地自行检查,否则请相信official javadoc,此处引用:
close 的一般约定是关闭输出流。一种 关闭的流无法执行输出操作,也无法重新打开。
OutputStream 的 close 方法什么都不做。
不管close()是否刷新,最安全的方法应该是手动刷新。如果它再次被冲洗,谁在乎?
“Tom Hawtin - tackline”的答案包含有关安全关闭流的更多详细信息(但并未真正清楚地回答原始问题 =P)。
【讨论】: