在Java中,当我调用OutputStream.close()时,我是否总是需要先调用OutputStream.flush()?

Tom*_*ito 41 java file-io

如果我只是close()在输出流中调用,输出是保证的,还是需要我flush()总是调用?

Tom*_*ine 23

虽然close应该打电话flush,但它比那复杂一点......

首先,装饰器(例如BufferedOutputStream)在Java中很常见.装饰器的构造可能会失败,因此您需要包含装饰器closefinally块中的"原始"流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();
}
Run Code Online (Sandbox Code Playgroud)

最重要的是,装饰器close方法通常不正确地实现.这包括一些java.io直到最近.

当然,你可能想要使用Execute Around习语来保持DRY(ish).


ZZ *_*der 22

关闭()总是刷新,所以不需要打电话.

编辑:这个答案是基于常识和我遇到的所有输出流.谁将为缓冲流实现close()而不先刷新缓冲区?在close()之前调用flush是没有害处的.但是,如果过度调用flush()会产生后果.它可能会在缓冲机制下失败.

  • Java文档中的任何相关链接都说它适用于所有输出流?据我所知,虽然API在一些类中给出了保证,但在其他类中,没有这样的保证. (10认同)
  • 这个答案是错误的,虽然高度投票.OutputStream的实现中没有任何内容强制执行该操作,并且javadoc未指定与此肯定相关的任何合同. (9认同)
  • 默认情况下,close()什么都不做.无法保证在您的实现中调用flush() (6认同)

bri*_*rns 5

如果您希望刷新流,则,请flush()在调用之前调用close()

尽管所有其他答案都相反(但正如某些评论中正确指出的那样), 的默认实现java.io.OutputStream::close() 不会调用flush(). 事实上,它什么都不做。如果您有源代码发行版,您可以自己轻松查看,否则只需相信官方 javadoc,引用此处:

close 的一般约定是它关闭输出流。关闭的流无法执行输出操作,也无法重新打开。

OutputStream 的 close 方法什么也不做。

不管是否close()冲水,最安全的做法应该是手动冲水。如果它再次发红,谁在乎?

“Tom Hawtin-tackline”的答案有关于安全关闭流的额外细节(但并没有真正清楚地回答原始问题=P)。


Jin*_*won 5

这里有很多危险的答案和评论。继续阅读我为什么使用危险这个词。

先说第一件事。检查这些。

你会发现没有一个语句是 say close()will call 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?
}
Run Code Online (Sandbox Code Playgroud)

事情可能已经改变了,但我在大约十年前亲身经历过。上面的源代码(客户端)在 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?
    }
}
Run Code Online (Sandbox Code Playgroud)

另请注意,这flush()并不意味着将数据写入/发送到物理磁盘或远程端点。大多数情况下,它只是将 JVM 中的缓冲数据刷新到底层操作系统中。


勘误表

Writer#close() 明确表示它

关闭流,首先冲洗它。

但这并不意味着所有子类都保留这个根契约。看看PrintWriter#close()哪个(没有flush())关闭了内部outWriter),这又取决于一个outclose()实现。