BufferedInputStreampublic class BufferedInputStream extends FilterInputStream Wraps an existing {@link InputStream} and buffers the input.
Expensive interaction with the underlying input stream is minimized, since
most (smaller) requests can be satisfied by accessing the buffer alone. The
drawback is that some extra space is required to hold the buffer and that
copying takes place when filling that buffer, but this is usually outweighed
by the performance benefits.
A typical application pattern for the class looks like this:
BufferedInputStream buf = new BufferedInputStream(new FileInputStream("file.java"));
|
Fields Summary |
---|
protected volatile byte[] | bufThe buffer containing the current bytes read from the target InputStream. | protected int | countThe total number of bytes inside the byte array {@code buf}. | protected int | marklimitThe current limit, which when passed, invalidates the current mark. | protected int | markposThe currently marked position. -1 indicates no mark has been set or the
mark has been invalidated. | protected int | posThe current position within the byte array {@code buf}. | private boolean | closed |
Constructors Summary |
---|
public BufferedInputStream(InputStream in)Constructs a new {@code BufferedInputStream} on the {@link InputStream}
{@code in}. The default buffer size (8 KB) is allocated and all reads
can now be filtered through this stream.
super(in);
buf = new byte[8192];
// BEGIN android-added
/*
* For Android, we want to discourage the use of this constructor (with
* its arguably too-large default), so we note its use in the log. We
* don't disable it, nor do we alter the default, however, because we
* still aim to behave compatibly, and the default value, though not
* documented, is established by convention.
*/
Logger.global.info(
"Default buffer size used in BufferedInputStream " +
"constructor. It would be " +
"better to be explicit if an 8k buffer is required.");
// END android-added
| public BufferedInputStream(InputStream in, int size)Constructs a new {@code BufferedInputStream} on the {@link InputStream}
{@code in}. The buffer size is specified by the parameter {@code size}
and all reads are now filtered through this stream.
super(in);
if (size <= 0) {
// K0058=size must be > 0
throw new IllegalArgumentException(Msg.getString("K0058")); //$NON-NLS-1$
}
buf = new byte[size];
|
Methods Summary |
---|
public synchronized int | available()Returns the number of bytes that are available before this stream will
block. This method returns the number of bytes available in the buffer
plus those available in the source stream.
if (buf == null) {
// K0059=Stream is closed
throw new IOException(Msg.getString("K0059")); //$NON-NLS-1$
}
return count - pos + in.available();
| public synchronized void | close()Closes this stream. The source stream is closed and any resources
associated with it are released.
if (null != in) {
super.close();
in = null;
}
buf = null;
closed = true;
| private int | fillbuf()
if (markpos == -1 || (pos - markpos >= marklimit)) {
/* Mark position not set or exceeded readlimit */
int result = in.read(buf);
if (result > 0) {
markpos = -1;
pos = 0;
count = result == -1 ? 0 : result;
}
return result;
}
if (markpos == 0 && marklimit > buf.length) {
/* Increase buffer size to accomodate the readlimit */
int newLength = buf.length * 2;
if (newLength > marklimit) {
newLength = marklimit;
}
byte[] newbuf = new byte[newLength];
System.arraycopy(buf, 0, newbuf, 0, buf.length);
buf = newbuf;
} else if (markpos > 0) {
System.arraycopy(buf, markpos, buf, 0, buf.length - markpos);
}
/* Set the new position and mark position */
pos -= markpos;
count = markpos = 0;
int bytesread = in.read(buf, pos, buf.length - pos);
count = bytesread <= 0 ? pos : pos + bytesread;
return bytesread;
| public synchronized void | mark(int readlimit)Sets a mark position in this stream. The parameter {@code readlimit}
indicates how many bytes can be read before a mark is invalidated.
Calling {@code reset()} will reposition the stream back to the marked
position if {@code readlimit} has not been surpassed. The underlying
buffer may be increased in size to allow {@code readlimit} number of
bytes to be supported.
marklimit = readlimit;
markpos = pos;
| public boolean | markSupported()Indicates whether {@code BufferedInputStream} supports the {@code mark()}
and {@code reset()} methods.
return true;
| public synchronized int | read()Reads a single byte from this stream and returns it as an integer in the
range from 0 to 255. Returns -1 if the end of the source string has been
reached. If the internal buffer does not contain any available bytes then
it is filled from the source stream and the first byte is returned.
if (in == null) {
// K0059=Stream is closed
throw new IOException(Msg.getString("K0059")); //$NON-NLS-1$
}
/* Are there buffered bytes available? */
if (pos >= count && fillbuf() == -1) {
return -1; /* no, fill buffer */
}
/* Did filling the buffer fail with -1 (EOF)? */
if (count - pos > 0) {
return buf[pos++] & 0xFF;
}
return -1;
| public synchronized int | read(byte[] buffer, int offset, int length)Reads at most {@code length} bytes from this stream and stores them in
byte array {@code buffer} starting at offset {@code offset}. Returns the
number of bytes actually read or -1 if no bytes were read and the end of
the stream was encountered. If all the buffered bytes have been used, a
mark has not been set and the requested number of bytes is larger than
the receiver's buffer size, this implementation bypasses the buffer and
simply places the results directly into {@code buffer}.
if (closed) {
// K0059=Stream is closed
throw new IOException(Msg.getString("K0059")); //$NON-NLS-1$
}
// avoid int overflow
// BEGIN android-changed
// Exception priorities (in case of multiple errors) differ from
// RI, but are spec-compliant.
// made implicit null check explicit, used (offset | length) < 0
// instead of (offset < 0) || (length < 0) to safe one operation
if (buffer == null) {
throw new NullPointerException(Msg.getString("K0047")); //$NON-NLS-1$
}
if ((offset | length) < 0 || offset > buffer.length - length) {
throw new IndexOutOfBoundsException(Msg.getString("K002f")); //$NON-NLS-1$
}
// END android-changed
if (length == 0) {
return 0;
}
if (null == buf) {
throw new IOException(Msg.getString("K0059")); //$NON-NLS-1$
}
int required;
if (pos < count) {
/* There are bytes available in the buffer. */
int copylength = count - pos >= length ? length : count - pos;
System.arraycopy(buf, pos, buffer, offset, copylength);
pos += copylength;
if (copylength == length || in.available() == 0) {
return copylength;
}
offset += copylength;
required = length - copylength;
} else {
required = length;
}
while (true) {
int read;
/*
* If we're not marked and the required size is greater than the
* buffer, simply read the bytes directly bypassing the buffer.
*/
if (markpos == -1 && required >= buf.length) {
read = in.read(buffer, offset, required);
if (read == -1) {
return required == length ? -1 : length - required;
}
} else {
if (fillbuf() == -1) {
return required == length ? -1 : length - required;
}
read = count - pos >= required ? required : count - pos;
System.arraycopy(buf, pos, buffer, offset, read);
pos += read;
}
required -= read;
if (required == 0) {
return length;
}
if (in.available() == 0) {
return length - required;
}
offset += read;
}
| public synchronized void | reset()Resets this stream to the last marked location.
// BEGIN android-changed
/*
* These exceptions get thrown in some "normalish" circumstances,
* so it is preferable to avoid loading up the whole big set of
* messages just for these cases.
*/
if (closed) {
throw new IOException("Stream is closed");
}
if (-1 == markpos) {
throw new IOException("Mark has been invalidated.");
}
// END android-changed
pos = markpos;
| public synchronized long | skip(long amount)Skips {@code amount} number of bytes in this stream. Subsequent
{@code read()}'s will not return these bytes unless {@code reset()} is
used.
if (null == in) {
// K0059=Stream is closed
throw new IOException(Msg.getString("K0059")); //$NON-NLS-1$
}
if (amount < 1) {
return 0;
}
if (count - pos >= amount) {
pos += amount;
return amount;
}
long read = count - pos;
pos = count;
if (markpos != -1) {
if (amount <= marklimit) {
if (fillbuf() == -1) {
return read;
}
if (count - pos >= amount - read) {
pos += amount - read;
return amount;
}
// Couldn't get all the bytes, skip what we read
read += (count - pos);
pos = count;
return read;
}
markpos = -1;
}
return read + in.skip(amount - read);
|
|