Buffered input streams read more data than they initially need into a
buffer (an internal array of bytes). When the stream’s
read()
methods are invoked, the data is removed
from the buffer rather than 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 gain.
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 4096 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.developer.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.macfaq.io; import java.io.*; public class BufferedStreamCopier { public static void main(String[] args) { try { copy(System.in, System.out); } catch (IOException e) {System.err.println(e);} } public static void copy(InputStream in, OutputStream out) throws IOException { // Do not allow other threads to read from the input // or write to the output while copying is taking place. synchronized (in) { synchronized (out) { 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.
It wouldn’t hurt to read and write byte arrays in the
copy()
method instead of individual bytes, as long
as the arrays you were reading and writing were significantly smaller
than the buffer size. However, one level of buffering is usually
sufficient. Detailed performance calculations depend on the virtual
machine and the host OS, so it’s hard to make any definite
conclusions.
Also note that the output stream is deliberately flushed. The data
only reaches its eventual destination in the underlying stream
out
when the stream is flushed or the buffer fills
up. Therefore, it’s important to call
flush()
explicitly before the method returns.
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 be- fore 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
BufferedInputStream
only overrides methods from
InputStream
. It does not declare any new methods
of its own. Marking and resetting are supported.
public synchronized int read() throws IOException public synchronized int read(byte[] data, int offset, int length) throws IOException public synchronized long skip(long n) throws IOException public synchronized int available() throws IOException public synchronized void mark(int readLimit) public synchronized void reset() throws IOException public boolean markSupported()
In Java 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. This is not the
case for most input streams (including buffered input streams in Java
1.1.x and earlier), which only attempt one read
from the underlying stream or data source before returning.
BufferedOutputStream
also stores the buffer 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
BufferedOutputStream
only overrides three methods
from OutputStream
. It does not declare any new
methods.
public synchronized void write(int b) throws IOException public synchronized void write(byte data[], int offset, int length) throws IOException public synchronized void flush() throws IOException
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.
3.147.53.166