In Java, when I call OutputStream.close() do I always need to call OutputStream.flush() before?
Asked Answered
P

4

51

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

Physiological answered 28/4, 2010 at 18:46 Comment(1)
You should accept @TomHawtin's answerSubstantive
C
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.

Charqui answered 28/4, 2010 at 18:47 Comment(4)
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.Preprandial
by default close() does nothing. There's no guarantee that flush() will be called in your implementationCurtsey
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.Connect
@Connect See FilterOutputStream.close().Michelinamicheline
D
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 ...
}
Disentangle answered 28/4, 2010 at 20:6 Comment(9)
Are the above said badly-implemented decorators include the JDK's API or just subclasses from the present decorators?Preprandial
@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).Disentangle
@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 patternSubstantive
@TomHawtin-tackline In your code example why did you chose not to call close() on the decorator? You wrote "In the case of an exception, you don't usually need to close the decorator" (emphasis mine). would like to understand the reasoning behind this. Can you please explain?Responsive
@Responsive 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.Disentangle
@TomHawtin-tackline The last line of your previous comment says "The Execute Around idiom can prevent duplication (implementation once per resource) of this mess, and isn't so verbose any more". Did you mean implementation of close() or is there something more to it?Responsive
@Responsive Just doing the acquire and release with correct behaviour in case of exceptions.Disentangle
In case a decorator failure, why do you worry about flush()?Charqui
@ZZCoder If the construction of the decorator fails and you try to flush it, then you'll get a NullPointerException. (Null-masking libraries are available, but that's hiding the problem and adds complexity.)Disentangle
C
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.

Charqui answered 28/4, 2010 at 18:47 Comment(4)
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.Preprandial
by default close() does nothing. There's no guarantee that flush() will be called in your implementationCurtsey
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.Connect
@Connect See FilterOutputStream.close().Michelinamicheline
N
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).

Nominative answered 26/4, 2016 at 19:57 Comment(1)
I strongly recommand this answer to the checked one :) Common sense is not necessarily correctKristiankristiansand
J
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.

Jablonski answered 12/8, 2016 at 6:32 Comment(5)
Excessive flushing defeats purpose of buffering. In your case of FileOutputStream(), it may cause unnecessary disk write.Charqui
@ZZCoder Do you have any concrete clue that closing the FileOutputStream will writes all written data?Jablonski
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().Charqui
@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.Jablonski
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.Michelinamicheline

© 2022 - 2024 — McMap. All rights reserved.