In Java, when I call OutputStream.close() do I always need to call OutputStream.flush() before?
If I just call close()
in a out开发者_运维百科put stream, the output is guaranteed, or need I call flush()
always?
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 ...
}
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.
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).
There are so many dangerous answers and comments here. Keep read why I used the word dangerous.
First things first. Check these out.
AutoCloseable#close()
Closeable#close()
OutputStream#close()
Writer#close()
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.
精彩评论