I understand the theory behind BufferedOutputStream
. Bytes are written to a buffer array until it is full, and then written (flushed) to the underlying stream - the idea being that it is faster than writing byte-by-byte as there are fewer OS calls.
However, from looking at the implementation of the BufferedOutputStream
class and methods (BufferedOutputStream.java), it seems that ultimately, the bytes from the buffer are just written byte-by-byte.
I think this is the case because:
In BufferedOutputStream.write(byte b[], int off, int len) it has the line out.write(b, off, len). Since out is an instance of OutputStream, but not BufferedOutputStream, it is calling OutputStream.write(byte[], int, int). This in turn uses a for loop to write byte-by-byte
Please could someone clarify what is actually going on, and how it is faster?
When the data is flushed, it is as a block.
79 /** Flush the internal buffer */
80 private void flushBuffer() throws IOException {
81 if (count > 0) {
82 out.write(buf, 0, count);
83 count = 0;
84 }
85 }
FileOutputStream and many other override OutputStream.write() to handle blocks of data efficiently.
http://www.docjar.com/html/api/java/io/FileOutputStream.java.html
284
285 /**
286 * Writes a sub array as a sequence of bytes.
287 * @param b the data to be written
288 * @param off the start offset in the data
289 * @param len the number of bytes that are written
290 * @param append {@code true} to first advance the position to the
291 * end of file
292 * @exception IOException If an I/O error has occurred.
293 */
294 private native void writeBytes(byte b[], int off, int len, boolean append)
295 throws IOException;
308 /**
309 * Writes <code>len</code> bytes from the specified byte array
310 * starting at offset <code>off</code> to this file output stream.
311 *
312 * @param b the data.
313 * @param off the start offset in the data.
314 * @param len the number of bytes to write.
315 * @exception IOException if an I/O error occurs.
316 */
317 public void write(byte b[], int off, int len) throws IOException {
318 writeBytes(b, off, len, append);
319 }
From your link:
/** Flush the internal buffer */
private void flushBuffer() throws IOException {
if (count > 0) {
out.write(buf, 0, count);
count = 0;
}
}
...
/**
* Flushes this buffered output stream. This forces any buffered
* output bytes to be written out to the underlying output stream.
*
* @exception IOException if an I/O error occurs.
* @see java.io.FilterOutputStream#out
*/
public synchronized void flush() throws IOException {
flushBuffer();
out.flush();
}
As you can see, the flush()
writes all the buffer contents in one go to the underlying stream and then cascades the flushing. BufferedOutputStream
then reimplements write(byte b[], int off, int len)
and void write(int b)
(the core methods in the class to which every write is delegated) so that it writes into the buffer, flushing when necessary.
The code states:
79 /** Flush the internal buffer */
80 private void flushBuffer() throws IOException {
81 if (count > 0) {
82 out.write(buf, 0, count);
83 count = 0;
84 }
85 }
This is a write of all the currently buffered bytes. Not byte-by-byte.
The idea is that the user of BufferedOutputStream
does not have to wait for every byte to be really sent. The user just can push a larger block to the outputstream and continue, even if the connection itself is slow. So it is faster on this side. The outputstream itself tries to be as fast as possible.
来源:https://stackoverflow.com/questions/9282909/how-does-bufferedoutputstream-actually-work-at-a-low-level