5

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?

user1209776
  • 157
  • 1
  • 3
  • 8
  • 1
    Buffer is flushed using `out.write(bytes ,offset, length)` how is that byte-by-byte? Can you be more specific? – Piotr Praszmo Feb 14 '12 at 19:34
  • 1
    But doesn't out.write(bytes ,offset, length) call the write(byte b[], int off, int len) method in OutputStream.java? Which then uses a for loop to write each byte in the buffer individually? – user1209776 Feb 14 '12 at 19:39
  • 3
    `OutputStream` is abstract. Most subclasses will overide this method with more efficient version. Look at [FileOutputStream](http://www.docjar.com/html/api/java/io/FileOutputStream.java.html) for example. – Piotr Praszmo Feb 14 '12 at 19:42
  • Comments on [Behind the scenes of Java's BufferedInputStream](https://stackoverflow.com/questions/49672561/behind-the-scenes-of-javas-bufferedinputstream) OP could help. – lupchiazoem Apr 06 '18 at 06:02

4 Answers4

2

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       }
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • If write(buffer, start, len) is not overridden, the buffer is pointless. Most streams do override it. – Peter Lawrey Feb 14 '12 at 19:45
  • In BufferedOutputStream.write(byte b[], int off, int len) it has the write out.write(b, off, len). Which write does this refer to? – user1209776 Feb 14 '12 at 20:07
  • Is it not OutputStream.write(byte[], int, int) ? – user1209776 Feb 14 '12 at 20:36
  • Which in turn, uses a for loop to write byte-by-byte? – user1209776 Feb 14 '12 at 20:45
  • Not if its overridden, which it usually is. e.g. In `FileOutputStream.write(byte[], int, int)` – Peter Lawrey Feb 15 '12 at 10:04
  • But the out used in the call out.write(b, off, len) is an instance of OutputStream, but it is not an instance of BufferedOutputStream. So would it not still use OutputStream.write(byte[], int, int) ? – user1209776 Feb 15 '12 at 19:59
  • You are right in the first statement. You realise the `out` is not actually an `OutputStream` but a sub-class. – Peter Lawrey Feb 15 '12 at 22:11
  • I'm saying the opposite. I'm saying it is an OutputStream, but not a BufferedOutputStream or instance of any other subclass. – user1209776 Feb 19 '12 at 22:37
  • OutputStream is abstract so you can't create an instance of this class, only a sub-class which much override at least one method, and I would expect usually override others. – Peter Lawrey Feb 19 '12 at 22:44
  • Ah of course, that makes sense. What I still don't understand though is the following. In BufferedOutputStream.java, write calls flushBuffer, and flushBuffer calls write. It seems like some sort of infinite loop. Where does the call to the OS actually happen? – user1209776 Feb 22 '12 at 19:52
  • It calls a different, overloaded write method. – Peter Lawrey Feb 23 '12 at 08:12
  • I must be misunderstanding, but it seems to me that flushBuffer() calls write(byte[], int, int) and write(byte[], int, int) calls flushBuffer() – user1209776 Feb 27 '12 at 19:35
  • flushBuffer() calls the `out.write(byte[], int, int);` of a *different* object. That object wouldn't implement flushBuffer() – Peter Lawrey Feb 27 '12 at 19:48
  • Underlying streams(like `FileOutputStream`) do provide bulk write(which are actually handled by native calls). `BufferedOutputStream` is just a helper-like-object to manage in-memory contents. Otherwise, the code has to manage buffering-things by itself. Courtesy: @kayaman – lupchiazoem Apr 06 '18 at 06:08
1

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.

gpeche
  • 21,974
  • 5
  • 38
  • 51
0

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.

Paul Grime
  • 14,970
  • 4
  • 36
  • 58
  • But doesn't write(buf, 0, count) work by doing it byte-by-byte? ... for (int i = 0 ; i < len ; i++) { write(b[off + i]); } ... – user1209776 Feb 14 '12 at 19:45
0

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.

Hauke Ingmar Schmidt
  • 11,559
  • 1
  • 42
  • 50