Buffered Streams
Buffered input streams read more data than they initially need into a buffer (an internal array of bytes). When one of the stream's read( ) methods is invoked, data is removed from the buffer rather than from the underlying stream. When the buffer runs out of data, the buffered stream refills its buffer from the underlying stream. Likewise, buffered output streams store data in an internal byte array until the buffer is full or the stream is flushed; then the data is written out to the underlying output stream in one swoop. In situations where it's almost as fast to read or write several hundred bytes from the underlying stream as it is to read or write a single byte, a buffered stream can provide a significant performance boost.
There are two BufferedInputStream constructors and two BufferedOutputStream constructors:
public BufferedInputStream(InputStream in) public BufferedInputStream(InputStream in, int size) public BufferedOutputStream(OutputStream out) public BufferedOutputStream(OutputStream out, int size)
The first argument is the underlying stream from which data will be read or to which data will be written. The size argument is the number of bytes in the buffer. If a size isn't specified, a 2048-byte buffer is used. The best size for the buffer depends on the platform and is generally related to the block size of the disk (at least for file streams). Less than 512 bytes is probably too small and more than 8,192 bytes is probably too large. Ideally, you want an integral multiple of the block size of the disk. However, you might want to use smaller buffer sizes for unreliable network connections. For example:
URL u = new URL("http://java.sun.com"); BufferedInputStream bis = new BufferedInputStream(u.openStream( ), 256);
Example 6-4 copies files named on the command line to System.out with buffered reads and writes.
Example 6-4. A BufferedStreamCopier
package com.elharo.io; import java.io.*; public class BufferedStreamCopier { public static void main(String[] args) { try { copy(System.in, System.out); } catch (IOException ex) { System.err.println(ex); } } public static void copy(InputStream in, OutputStream out) throws IOException { BufferedInputStream bin = new BufferedInputStream(in); BufferedOutputStream bout = new BufferedOutputStream(out); while (true) { int datum = bin.read( ); if (datum == -1) break; bout.write(datum); } bout.flush( ); } } |
This copy( ) method copies byte by byte, which is normally not very efficient. However, almost all the copies take place in memory, because the input stream and the output stream are buffered. Therefore, this is reasonably quick.
The output stream is deliberately flushed. The data reaches its eventual destination in the underlying stream out only when the stream is flushed or the buffer fills up. Therefore, it's important to call flush( ) explicitly before the method returns.
6.3.1. BufferedInputStream Details
BufferedInputStream only overrides and inherits methods from InputStream. It does not declare any new methods of its own. Marking and resetting are supported.
In Java 1.2 and later, the two multibyte read( ) methods try to fill the specified array or subarray completely by reading repeatedly from the underlying input stream. They return only when the requested number of bytes have been read, the end of stream is reached, or the underlying stream would block. Most other input streams attempt only one read from the underlying stream or data source before returning.
The buffer and the current state of the buffer are stored in protected fields. The buffer itself is a byte array called buf; the number of bytes in the buffer is an int named count; the index of the next byte that will be returned by read( ) is an int called pos; the mark, if any, is an int called markpos; the read-ahead limit before the mark is invalidated is an int called marklimit. Subclasses of BufferedInputStream can directly access all these fields, which can be important for performance.
protected byte[] buf protected int count protected int pos protected int markpos protected int marklimit
6.3.2. BufferedOutputStream Details
BufferedOutputStream stores the buffered data in a protected byte array named buf and the index of the next place in the array where a byte will be stored in an int field named pos. BufferedOutputStream does not expose the number of bytes in the buffer.
protected byte buf[] protected int pos
Otherwise, BufferedOutputStream has the same write( ), flush( ), and close( ) methods every OutputStream has. These methods are invoked exactly as they would be for any output stream. The only difference is that writes place data in the buffer rather than directly on the underlying output stream. BufferedOutputStream does not declare any new methods.