Java BufferedOutputStream
Jakob Jenkov |
The Java BufferedOutputStream class, java.io.BufferedOutputStream, is used to capture bytes written to the BufferedOutputStream in a buffer, and write the whole buffer in one batch to an underlying Java OutputStream for increased performance. Buffering can speed up IO quite a bit, especially when writing data to disk access or network.
Create a BufferedOutputStream
To add buffering to your OutputStream
's simply wrap them in a BufferedOutputStream
.
Here is an example of wrapping an OutputStream
in a BufferedOutputStream
:
OutputStream output = new BufferedOutputStream( new FileOutputStream("c:\\data\\output-file.txt"));
Simple, isn't it?
Setting Buffer Size of a BufferedOutputStream
You can set the buffer size to use internally by in a Java BufferedOutputStream
.
You provide the size as a constructor parameter, like this:
int bufferSize = 8 * 1024; OutputStream output = new BufferedOutputStream( new FileOutputStream("c:\\data\\output-file.txt"), bufferSize );
This example sets the internal buffer to 8 KB. It is best to use buffer sizes that are multiples of 1024 bytes. That works best with most built-in buffering in hard disks etc.
Except for adding buffering to your input streams, the Java BufferedOutputStream
behaves exactly
like an OutputStream
. The only difference is that you may need to call flush()
if you need to be absolutely sure that the data written until now is flushed out of the buffer and onto
the network or disk.
Optimal Buffer Size for a BufferedOutputStream
You should make some experiments with different buffer sizes to find out which buffer size
seems to give you the best performance on your concrete hardware. The optimal buffer size may depend on whether
you are using the Java BufferedOutputStream
with a disk or network OutputStream
.
With both disk and network streams, the optimal buffer size may also depend on the concrete hardware in the computer. If the hard disk is anyways writing a minimum of 4KB at a time, it's stupid to use less than a 4KB buffer. It is also better to then use a buffer size that is a multiple of 4KB. For instance, using 6KB would be stupid too.
Even if your disk writes blocks of e.g. 4KB at a time, it can still be a good idea to use a buffer that is larger
than this. A disk is good at writing data sequentially - meaning it is good at writing multiple blocks that are
located after each other. Thus, using a 16KB buffer, or a 64KB buffer (or even larger)
with a BufferedOutputStream
may still give you a better performance than using just a 4KB buffer.
To find the optimal BufferedOutputStream
buffer size, find out the block size your hard disk writes
in, and make the buffer a multiple of that size. You will definitely have to
experiment to find the optimal buffer size. Do so by measuring write speeds with different buffer sizes.
write()
To write data to a Java BufferedOutputStream
you can use its write()
method.
The write()
method takes an int
which contains the byte value of the
byte to write. Thus, only the lower 8 bit of the passed int
actually gets written to
the BufferedOutputStream
destination. Here is an example of writing data to a
Java BufferedOutputStream
using its write()
method:
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("c:\\data\\output-text.txt")); bufferedOutputStream.write(123);
This example writes the byte value 123
to the given Java BufferedOutputStream
.
Writing Byte Arrays
Since the Java BufferedOutputStream
is a subclass of OutputStream
, you can write arrays of
bytes to the BufferedOutputStream
too, instead of just a single byte at a time. Here is an example
of writing an array of bytes to a Java BufferedOutputStream
:
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("c:\\data\\output-text.txt")); byte bytes = new byte[]{1,2,3,4,5}; outputStream.write(bytes);
flush()
When you write data to a Java BufferedOutputStream
the data is cached internally in a byte buffer
until the byte buffer is full, at which time the whole buffer is written to the underlying
OutputStream
.
If you want to make sure that all written data is written to disk without having to close the BufferedOutputStream
you can call its flush()
method. Calling flush()
will make sure that all data which has
been written to the BufferedOutputStream
so far, is fully written to the underlying
OutputStream
too, plus flush()
will also have been called on the underlying
OutputStream
.
Here is an example of calling the Java BufferedOutputStream
flush()
method:
OutputStream outputStream = new BufferedOutputStream(new FileOutputStream("c:\\data\\output-text.txt")); byte bytes = new byte[]{1,2,3,4,5}; outputStream.write(bytes); outputStream.flush()
Closing a BufferedOutputStream
Once you are done writing data to a Java BufferedOutputStream
you should close it. You close an
BufferedOutputStream
by calling its close()
method. Closing a
BufferedOutputStream
also closes the underlying OutputStream
that the
BufferedOutputStream
is reading data from.
Here is an example of closing a Java BufferedOutputStream
:
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream( new FileOutputStream("c:\\data\\output-file.txt")); while(hasMoreData()) { int data = getMoreData(); bufferedOutputStream.write(data); } bufferedOutputStream.close();
The concrete implementations of hasMoreData()
and getMoreData()
are left out, but
they are not really super important to understand the principle of this example. What matters is, that
once the while
loop ends, and you are done writing data to the BufferedOutputStream
,
its close()
method is called, which closes the BufferedOutputStream
.
The above example is not fully robust though. In case the write()
method throws an exception,
the close()
method will never get called. The exception will make the program exit whatever
method the above code is located in.
Instead, you should use the
Java try with resources construct to close
the BufferedOutputStream
. Here is an example that closes a Java BufferedOutputStream
using
the try-with-resources construct:
try( BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("c:\\data\\output-text.txt"))) { while(hasMoreData()) { int data = getMoreData(); output.write(data); } }
Once the try
block is exited, the close()
method of the BufferedOutputStream
is called automatically, because the BufferedOutputStream
was declared inside the parentheses of the
try
block. Even if an exception is thrown from inside the try
block, the
close()
method is still called before the exception is propagated up the call stack.
Tweet | |
Jakob Jenkov |