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

时间:2010-04-28 18:46:53

标签: java file-io

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

4 个答案:

答案 0 :(得分:23)

虽然close应该致电flush,但这比那更复杂......

首先,装饰器(例如BufferedOutputStream)在Java中很常见。装饰器的构造可能会失败,因此您需要close finally块中的{raw}流,其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)。

答案 1 :(得分:22)

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

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

答案 2 :(得分:4)

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

首先要做的事情。看看这些。

您会发现没有一条声明说close()会致电flush()。如果我错过任何一个,请修复我。

当您需要或需要保证至少刷新到OS级别的缓冲数据时,请使用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())关闭内部outWriter),这又取决于out&#39; {{1}实施。

答案 3 :(得分:3)

如果您想要刷新流,然后,请在致电JSON.stringify()之前致电var stringifyMe = { tokenValue: '36151b9e-ad0d-49de-a14b-5461489c7065' }; var stringified = JSON.stringify(stringifyMe); // stringified is now equal to the string {"tokenValue":"36151b9e-ad0d-49de-a14b-5461489c7065"}

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

  

close的一般合约是关闭输出流。一个   封闭流无法执行输出操作,无法重新打开。

     

OutputStream的close方法不执行任何操作。

无论java.io.OutputStream::close()是否刷新,最安全的方法应该是手动刷新。如果它再次被冲洗,谁在乎呢?

Tom Hawtin的回答 - 强调&#34;有关于安全关闭流的其他详细信息(但没有明确地回答原始问题= P)。