BufferedReaderpublic class BufferedReader extends Reader Wraps an existing {@link Reader} and buffers the input. Expensive
interaction with the underlying reader 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:
BufferedReader buf = new BufferedReader(new FileReader("file.java"));
|
Fields Summary |
---|
private Reader | in | private char[] | buf | private int | marklimit | private int | count | private int | markpos | private int | pos |
Constructors Summary |
---|
public BufferedReader(Reader in)Constructs a new BufferedReader on the Reader {@code in}. The
buffer gets the default size (8 KB).
super(in);
this.in = in;
buf = new char[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 BufferedReader " +
"constructor. It would be " +
"better to be explicit if an 8k-char buffer is required.");
// END android-added
| public BufferedReader(Reader in, int size)Constructs a new BufferedReader on the Reader {@code in}. The buffer
size is specified by the parameter {@code size}.
super(in);
if (size <= 0) {
throw new IllegalArgumentException(Msg.getString("K0058")); //$NON-NLS-1$
}
this.in = in;
buf = new char[size];
|
Methods Summary |
---|
public void | close()Closes this reader. This implementation closes the buffered source reader
and releases the buffer. Nothing is done if this reader has already been
closed.
synchronized (lock) {
if (!isClosed()) {
in.close();
buf = null;
}
}
| private int | fillbuf()
if (markpos == -1 || (pos - markpos >= marklimit)) {
/* Mark position not set or exceeded readlimit */
int result = in.read(buf, 0, buf.length);
if (result > 0) {
markpos = -1;
pos = 0;
count = result == -1 ? 0 : result;
}
return result;
}
if (markpos == 0 && marklimit > buf.length) {
/* Increase buffer size to accommodate the readlimit */
int newLength = buf.length * 2;
if (newLength > marklimit) {
newLength = marklimit;
}
char[] newbuf = new char[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 charsread = in.read(buf, pos, buf.length - pos);
count = charsread == -1 ? pos : pos + charsread;
return charsread;
| private boolean | isClosed()Indicates whether or not this reader is closed.
return buf == null;
| public void | mark(int readlimit)Sets a mark position in this reader. The parameter {@code readlimit}
indicates how many characters can be read before the mark is invalidated.
Calling {@code reset()} will reposition the reader back to the marked
position if {@code readlimit} has not been surpassed.
if (readlimit < 0) {
throw new IllegalArgumentException();
}
synchronized (lock) {
if (isClosed()) {
throw new IOException(Msg.getString("K005b")); //$NON-NLS-1$
}
marklimit = readlimit;
markpos = pos;
}
| public boolean | markSupported()Indicates whether this reader supports the {@code mark()} and
{@code reset()} methods. This implementation returns {@code true}.
return true;
| public int | read()Reads a single character from this reader and returns it with the two
higher-order bytes set to 0. If possible, BufferedReader returns a
character from the buffer. If there are no characters available in the
buffer, it fills the buffer and then returns a character. It returns -1
if there are no more characters in the source reader.
synchronized (lock) {
if (isClosed()) {
throw new IOException(Msg.getString("K005b")); //$NON-NLS-1$
}
/* Are there buffered characters available? */
if (pos < count || fillbuf() != -1) {
return buf[pos++];
}
return -1;
}
| public int | read(char[] buffer, int offset, int length)Reads at most {@code length} characters from this reader and stores them
at {@code offset} in the character array {@code buffer}. Returns the
number of characters actually read or -1 if the end of the source reader
has been reached. If all the buffered characters have been used, a mark
has not been set and the requested number of characters is larger than
this readers buffer size, BufferedReader bypasses the buffer and simply
places the results directly into {@code buffer}.
synchronized (lock) {
if (isClosed()) {
throw new IOException(Msg.getString("K005b")); //$NON-NLS-1$
}
// 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;
}
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.ready()) {
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.ready()) {
return length - required;
}
offset += read;
}
}
| public java.lang.String | readLine()Returns the next line of text available from this reader. A line is
represented by zero or more characters followed by {@code '\n'},
{@code '\r'}, {@code "\r\n"} or the end of the reader. The string does
not include the newline sequence.
synchronized (lock) {
if (isClosed()) {
throw new IOException(Msg.getString("K005b")); //$NON-NLS-1$
}
/* Are there buffered characters available? */
if ((pos >= count) && (fillbuf() == -1)) {
return null;
}
for (int charPos = pos; charPos < count; charPos++) {
char ch = buf[charPos];
if (ch > '\r") {
continue;
}
if (ch == '\n") {
String res = new String(buf, pos, charPos - pos);
pos = charPos + 1;
return res;
} else if (ch == '\r") {
String res = new String(buf, pos, charPos - pos);
pos = charPos + 1;
if (((pos < count) || (fillbuf() != -1))
&& (buf[pos] == '\n")) {
pos++;
}
return res;
}
}
char eol = '\0";
StringBuilder result = new StringBuilder(80);
/* Typical Line Length */
result.append(buf, pos, count - pos);
pos = count;
while (true) {
/* Are there buffered characters available? */
if (pos >= count) {
if (eol == '\n") {
return result.toString();
}
// attempt to fill buffer
if (fillbuf() == -1) {
// characters or null.
return result.length() > 0 || eol != '\0" ? result
.toString() : null;
}
}
for (int charPos = pos; charPos < count; charPos++) {
if (eol == '\0") {
if ((buf[charPos] == '\n" || buf[charPos] == '\r")) {
eol = buf[charPos];
}
} else if (eol == '\r" && (buf[charPos] == '\n")) {
if (charPos > pos) {
result.append(buf, pos, charPos - pos - 1);
}
pos = charPos + 1;
return result.toString();
} else if (eol != '\0") {
if (charPos > pos) {
result.append(buf, pos, charPos - pos - 1);
}
pos = charPos;
return result.toString();
}
}
if (eol == '\0") {
result.append(buf, pos, count - pos);
} else {
result.append(buf, pos, count - pos - 1);
}
pos = count;
}
}
| public boolean | ready()Indicates whether this reader is ready to be read without blocking.
synchronized (lock) {
if (isClosed()) {
throw new IOException(Msg.getString("K005b")); //$NON-NLS-1$
}
return ((count - pos) > 0) || in.ready();
}
| public void | reset()Resets this reader's position to the last {@code mark()} location.
Invocations of {@code read()} and {@code skip()} will occur from this new
location.
synchronized (lock) {
if (isClosed()) {
throw new IOException(Msg.getString("K005b")); //$NON-NLS-1$
}
if (markpos == -1) {
throw new IOException(Msg.getString("K005c")); //$NON-NLS-1$
}
pos = markpos;
}
| public long | skip(long amount)Skips {@code amount} characters in this reader. Subsequent
{@code read()}s will not return these characters unless {@code reset()}
is used. Skipping characters may invalidate a mark if {@code readlimit}
is surpassed.
if (amount < 0) {
throw new IllegalArgumentException();
}
synchronized (lock) {
if (isClosed()) {
throw new IOException(Msg.getString("K005b")); //$NON-NLS-1$
}
if (amount < 1) {
return 0;
}
if (count - pos >= amount) {
pos += amount;
return amount;
}
long read = count - pos;
pos = count;
while (read < amount) {
if (fillbuf() == -1) {
return read;
}
if (count - pos >= amount - read) {
pos += amount - read;
return amount;
}
// Couldn't get all the characters, skip what we read
read += (count - pos);
pos = count;
}
return amount;
}
|
|