52

If I just call close() in a output stream, the output is guaranteed, or need I call flush() always?

1
  • 2
    You should accept @TomHawtin's answer Commented Apr 15, 2014 at 14:03

4 Answers 4

29

Whilst close should call flush, it's a bit more complicated than that...

Firstly, decorators (such as BufferedOutputStream) are common in Java. Construction of the decorator may fail, so you need to close the "raw" stream in a finally block whose try includes the decorator. In the case of an exception, you don't usually need to close the decorator (except, for instance, for badly implemented compression decorators). You do typically need to flush the decorator in the non-exception case. Therefore:

final RawOutputStream rawOut = new RawOutputStream(rawThing);
try {
    final DecoratedOutputStream out = new DecoratedOutputStream(rawOut);
    // ... stuff with out within ...
    out.flush();
} finally {
    rawOut.close();
}

To top it, decorator close methods are often implemented incorrectly. That includes some in java.io until recently.

Of course, you probably want to use the Execute Around idiom to keep in DRY(ish).

Edit: Since Java 8 you can use try-with-resource statements that should handle everything nicely and concisely. The code will call close on each resource even if unnecessary.

try (
    RawOutputStream rawOut = new RawOutputStream(rawThing);
    DecoratedOutputStream out = new DecoratedOutputStream(rawOut)
) {
    // ... stuff with out within ...
}
Sign up to request clarification or add additional context in comments.

9 Comments

Are the above said badly-implemented decorators include the JDK's API or just subclasses from the present decorators?
@AseemBansal There are still some decorators in OpenJDK that use native resources themselves, so should be released explicitly. The behaviour is not documented. If they were using some exotic acceleration then that might be reasonable (they're not, they're just using grubby old C code sigh).
@McDowell suggests here something in the lines of:final RawOutputStream rawOut = new RawOutputStream(rawThing); Closeable resource = res; try { res = new DecoratedOutputStream(rawOut); /* etc */ res.flush(); } finally { res.close(); }. May be of interest as a pattern
@Geek The file or socket descriptor is the underlying resource that needs to be closed. The decorator does not need to be disposed of (unless it has, say, a C heap allocation). Attempting to use the decorator close leads to overcomplicated code and, more often than not, peculiar bugs. The Java I/O library is very badly designed, for instance having close on decorators, and unfortunately that has been carried over into an even worse design for Java SE 8 Stream. The Execute Around idiom can prevent duplication (implementation once per resource) of this mess, and isn't so verbose any more.
@Geek Just doing the acquire and release with correct behaviour in case of exceptions.
|
25

Close() always flushes so no need to call.

EDIT: This answer is based on common sense and all the outputstream I encountered. Who is going to implement a close() for a buffered stream without flushing buffer first? There is no harm to call flush right before close(). However, there are consequences if flush() is called excessively. It may defeat underneath buffering mechanism.

4 Comments

Any relevant link in Java documentation saying that it happens for all Output Streams? As far as I could find though the API the surety for this is given in some Classes while in others there is no such surety.
by default close() does nothing. There's no guarantee that flush() will be called in your implementation
this answer is wrong, though highly up-voted. Nothing in the implementation of OutputStream enforces that, and the javadoc does not specify any contract related to this affirmation.
@Jerome See FilterOutputStream.close().
6

If you want the stream to be flushed, then yes, call flush() before calling close().

Despite all the other answers to the contrary (but as noted correctly in some comments), the default implementation of java.io.OutputStream::close() does not call flush(). In fact, it does nothing. If you have a source distribution, you can easily check it out for yourself, otherwise just trust the official javadoc, quoted here:

The general contract of close is that it closes the output stream. A closed stream cannot perform output operations and cannot be reopened.

The close method of OutputStream does nothing.

Regardless of whether close() flushes or not, the safest approach should be to flush it manually. If it gets flushed again, who cares?

The answer by "Tom Hawtin - tackline" has additional details on safely closing streams (but doesn't really answer the original question clearly =P).

1 Comment

I strongly recommand this answer to the checked one :) Common sense is not necessarily correct
6

There are so many dangerous answers and comments here. Keep read why I used the word dangerous.

First things first. Check these out.

You shall find that there is no single statement that saying close() will call flush(). Fix me if I missed any.

Use flush() whenever you need to or need to guarantee the buffered data flushed at least into OS level.

flush() has its own purpose(s).

// 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?
}

Things might have been changed, but I experienced for myself about a decade ago. Above source code (client) worked with Windows XP and failed with Windows 2000 Server for a same endpoint(server).

And (you) do not (have to) rely on any implementation specific behaviour of 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?
    }
}

Note, also, that the flush() doesn't mean to writing/sending your data to physical disk or remote endpoint. It, mostly, just flushes the buffered data in the JVM into the underlying OS.


errata

Writer#close() explicitly says that it

closes the stream, flushing it first.

But it doesn't mean all subclasses keep this root contract. See PrintWriter#close() which (without flush()) closes the internal out(Writer) which, again, depends one the out's close() implementation.

5 Comments

Excessive flushing defeats purpose of buffering. In your case of FileOutputStream(), it may cause unnecessary disk write.
@ZZCoder Do you have any concrete clue that closing the FileOutputStream will writes all written data?
If the stream is not buffered like FileOutputStream, flush() does nothing. In Java, all buffered streams are implemented as decorator by subclassing FilterOutputStream, it calls flush() in close().
@ZZCoder Point of views such as yours yield questions OP asked. There is no contract that any FileOutputStream implementation should not override flush and should not buffer.
You didn't look in the right place. See FilterOutputStream.close(), and note that BufferedOutputStream extends it. Black swan fallacy. You only looked for white swans.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.