001: /*
002: * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package java.io;
027:
028: /**
029: * Reads text from a character-input stream, buffering characters so as to
030: * provide for the efficient reading of characters, arrays, and lines.
031: *
032: * <p> The buffer size may be specified, or the default size may be used. The
033: * default is large enough for most purposes.
034: *
035: * <p> In general, each read request made of a Reader causes a corresponding
036: * read request to be made of the underlying character or byte stream. It is
037: * therefore advisable to wrap a BufferedReader around any Reader whose read()
038: * operations may be costly, such as FileReaders and InputStreamReaders. For
039: * example,
040: *
041: * <pre>
042: * BufferedReader in
043: * = new BufferedReader(new FileReader("foo.in"));
044: * </pre>
045: *
046: * will buffer the input from the specified file. Without buffering, each
047: * invocation of read() or readLine() could cause bytes to be read from the
048: * file, converted into characters, and then returned, which can be very
049: * inefficient.
050: *
051: * <p> Programs that use DataInputStreams for textual input can be localized by
052: * replacing each DataInputStream with an appropriate BufferedReader.
053: *
054: * @see FileReader
055: * @see InputStreamReader
056: *
057: * @version 1.43, 07/05/05
058: * @author Mark Reinhold
059: * @since JDK1.1
060: */
061:
062: public class BufferedReader extends Reader {
063:
064: private Reader in;
065:
066: private char cb[];
067: private int nChars, nextChar;
068:
069: private static final int INVALIDATED = -2;
070: private static final int UNMARKED = -1;
071: private int markedChar = UNMARKED;
072: private int readAheadLimit = 0; /* Valid only when markedChar > 0 */
073:
074: /** If the next character is a line feed, skip it */
075: private boolean skipLF = false;
076:
077: /** The skipLF flag when the mark was set */
078: private boolean markedSkipLF = false;
079:
080: private static int defaultCharBufferSize = 8192;
081: private static int defaultExpectedLineLength = 80;
082:
083: /**
084: * Creates a buffering character-input stream that uses an input buffer of
085: * the specified size.
086: *
087: * @param in A Reader
088: * @param sz Input-buffer size
089: *
090: * @exception IllegalArgumentException If sz is <= 0
091: */
092: public BufferedReader(Reader in, int sz) {
093: super (in);
094: if (sz <= 0)
095: throw new IllegalArgumentException("Buffer size <= 0");
096: this .in = in;
097: cb = new char[sz];
098: nextChar = nChars = 0;
099: }
100:
101: /**
102: * Creates a buffering character-input stream that uses a default-sized
103: * input buffer.
104: *
105: * @param in A Reader
106: */
107: public BufferedReader(Reader in) {
108: this (in, defaultCharBufferSize);
109: }
110:
111: /** Checks to make sure that the stream has not been closed */
112: private void ensureOpen() throws IOException {
113: if (in == null)
114: throw new IOException("Stream closed");
115: }
116:
117: /**
118: * Fills the input buffer, taking the mark into account if it is valid.
119: */
120: private void fill() throws IOException {
121: int dst;
122: if (markedChar <= UNMARKED) {
123: /* No mark */
124: dst = 0;
125: } else {
126: /* Marked */
127: int delta = nextChar - markedChar;
128: if (delta >= readAheadLimit) {
129: /* Gone past read-ahead limit: Invalidate mark */
130: markedChar = INVALIDATED;
131: readAheadLimit = 0;
132: dst = 0;
133: } else {
134: if (readAheadLimit <= cb.length) {
135: /* Shuffle in the current buffer */
136: System.arraycopy(cb, markedChar, cb, 0, delta);
137: markedChar = 0;
138: dst = delta;
139: } else {
140: /* Reallocate buffer to accommodate read-ahead limit */
141: char ncb[] = new char[readAheadLimit];
142: System.arraycopy(cb, markedChar, ncb, 0, delta);
143: cb = ncb;
144: markedChar = 0;
145: dst = delta;
146: }
147: nextChar = nChars = delta;
148: }
149: }
150:
151: int n;
152: do {
153: n = in.read(cb, dst, cb.length - dst);
154: } while (n == 0);
155: if (n > 0) {
156: nChars = dst + n;
157: nextChar = dst;
158: }
159: }
160:
161: /**
162: * Reads a single character.
163: *
164: * @return The character read, as an integer in the range
165: * 0 to 65535 (<tt>0x00-0xffff</tt>), or -1 if the
166: * end of the stream has been reached
167: * @exception IOException If an I/O error occurs
168: */
169: public int read() throws IOException {
170: synchronized (lock) {
171: ensureOpen();
172: for (;;) {
173: if (nextChar >= nChars) {
174: fill();
175: if (nextChar >= nChars)
176: return -1;
177: }
178: if (skipLF) {
179: skipLF = false;
180: if (cb[nextChar] == '\n') {
181: nextChar++;
182: continue;
183: }
184: }
185: return cb[nextChar++];
186: }
187: }
188: }
189:
190: /**
191: * Reads characters into a portion of an array, reading from the underlying
192: * stream if necessary.
193: */
194: private int read1(char[] cbuf, int off, int len) throws IOException {
195: if (nextChar >= nChars) {
196: /* If the requested length is at least as large as the buffer, and
197: if there is no mark/reset activity, and if line feeds are not
198: being skipped, do not bother to copy the characters into the
199: local buffer. In this way buffered streams will cascade
200: harmlessly. */
201: if (len >= cb.length && markedChar <= UNMARKED && !skipLF) {
202: return in.read(cbuf, off, len);
203: }
204: fill();
205: }
206: if (nextChar >= nChars)
207: return -1;
208: if (skipLF) {
209: skipLF = false;
210: if (cb[nextChar] == '\n') {
211: nextChar++;
212: if (nextChar >= nChars)
213: fill();
214: if (nextChar >= nChars)
215: return -1;
216: }
217: }
218: int n = Math.min(len, nChars - nextChar);
219: System.arraycopy(cb, nextChar, cbuf, off, n);
220: nextChar += n;
221: return n;
222: }
223:
224: /**
225: * Reads characters into a portion of an array.
226: *
227: * <p> This method implements the general contract of the corresponding
228: * <code>{@link Reader#read(char[], int, int) read}</code> method of the
229: * <code>{@link Reader}</code> class. As an additional convenience, it
230: * attempts to read as many characters as possible by repeatedly invoking
231: * the <code>read</code> method of the underlying stream. This iterated
232: * <code>read</code> continues until one of the following conditions becomes
233: * true: <ul>
234: *
235: * <li> The specified number of characters have been read,
236: *
237: * <li> The <code>read</code> method of the underlying stream returns
238: * <code>-1</code>, indicating end-of-file, or
239: *
240: * <li> The <code>ready</code> method of the underlying stream
241: * returns <code>false</code>, indicating that further input requests
242: * would block.
243: *
244: * </ul> If the first <code>read</code> on the underlying stream returns
245: * <code>-1</code> to indicate end-of-file then this method returns
246: * <code>-1</code>. Otherwise this method returns the number of characters
247: * actually read.
248: *
249: * <p> Subclasses of this class are encouraged, but not required, to
250: * attempt to read as many characters as possible in the same fashion.
251: *
252: * <p> Ordinarily this method takes characters from this stream's character
253: * buffer, filling it from the underlying stream as necessary. If,
254: * however, the buffer is empty, the mark is not valid, and the requested
255: * length is at least as large as the buffer, then this method will read
256: * characters directly from the underlying stream into the given array.
257: * Thus redundant <code>BufferedReader</code>s will not copy data
258: * unnecessarily.
259: *
260: * @param cbuf Destination buffer
261: * @param off Offset at which to start storing characters
262: * @param len Maximum number of characters to read
263: *
264: * @return The number of characters read, or -1 if the end of the
265: * stream has been reached
266: *
267: * @exception IOException If an I/O error occurs
268: */
269: public int read(char cbuf[], int off, int len) throws IOException {
270: synchronized (lock) {
271: ensureOpen();
272: if ((off < 0) || (off > cbuf.length) || (len < 0)
273: || ((off + len) > cbuf.length) || ((off + len) < 0)) {
274: throw new IndexOutOfBoundsException();
275: } else if (len == 0) {
276: return 0;
277: }
278:
279: int n = read1(cbuf, off, len);
280: if (n <= 0)
281: return n;
282: while ((n < len) && in.ready()) {
283: int n1 = read1(cbuf, off + n, len - n);
284: if (n1 <= 0)
285: break;
286: n += n1;
287: }
288: return n;
289: }
290: }
291:
292: /**
293: * Reads a line of text. A line is considered to be terminated by any one
294: * of a line feed ('\n'), a carriage return ('\r'), or a carriage return
295: * followed immediately by a linefeed.
296: *
297: * @param ignoreLF If true, the next '\n' will be skipped
298: *
299: * @return A String containing the contents of the line, not including
300: * any line-termination characters, or null if the end of the
301: * stream has been reached
302: *
303: * @see java.io.LineNumberReader#readLine()
304: *
305: * @exception IOException If an I/O error occurs
306: */
307: String readLine(boolean ignoreLF) throws IOException {
308: StringBuffer s = null;
309: int startChar;
310:
311: synchronized (lock) {
312: ensureOpen();
313: boolean omitLF = ignoreLF || skipLF;
314:
315: bufferLoop: for (;;) {
316:
317: if (nextChar >= nChars)
318: fill();
319: if (nextChar >= nChars) { /* EOF */
320: if (s != null && s.length() > 0)
321: return s.toString();
322: else
323: return null;
324: }
325: boolean eol = false;
326: char c = 0;
327: int i;
328:
329: /* Skip a leftover '\n', if necessary */
330: if (omitLF && (cb[nextChar] == '\n'))
331: nextChar++;
332: skipLF = false;
333: omitLF = false;
334:
335: charLoop: for (i = nextChar; i < nChars; i++) {
336: c = cb[i];
337: if ((c == '\n') || (c == '\r')) {
338: eol = true;
339: break charLoop;
340: }
341: }
342:
343: startChar = nextChar;
344: nextChar = i;
345:
346: if (eol) {
347: String str;
348: if (s == null) {
349: str = new String(cb, startChar, i - startChar);
350: } else {
351: s.append(cb, startChar, i - startChar);
352: str = s.toString();
353: }
354: nextChar++;
355: if (c == '\r') {
356: skipLF = true;
357: }
358: return str;
359: }
360:
361: if (s == null)
362: s = new StringBuffer(defaultExpectedLineLength);
363: s.append(cb, startChar, i - startChar);
364: }
365: }
366: }
367:
368: /**
369: * Reads a line of text. A line is considered to be terminated by any one
370: * of a line feed ('\n'), a carriage return ('\r'), or a carriage return
371: * followed immediately by a linefeed.
372: *
373: * @return A String containing the contents of the line, not including
374: * any line-termination characters, or null if the end of the
375: * stream has been reached
376: *
377: * @exception IOException If an I/O error occurs
378: */
379: public String readLine() throws IOException {
380: return readLine(false);
381: }
382:
383: /**
384: * Skips characters.
385: *
386: * @param n The number of characters to skip
387: *
388: * @return The number of characters actually skipped
389: *
390: * @exception IllegalArgumentException If <code>n</code> is negative.
391: * @exception IOException If an I/O error occurs
392: */
393: public long skip(long n) throws IOException {
394: if (n < 0L) {
395: throw new IllegalArgumentException("skip value is negative");
396: }
397: synchronized (lock) {
398: ensureOpen();
399: long r = n;
400: while (r > 0) {
401: if (nextChar >= nChars)
402: fill();
403: if (nextChar >= nChars) /* EOF */
404: break;
405: if (skipLF) {
406: skipLF = false;
407: if (cb[nextChar] == '\n') {
408: nextChar++;
409: }
410: }
411: long d = nChars - nextChar;
412: if (r <= d) {
413: nextChar += r;
414: r = 0;
415: break;
416: } else {
417: r -= d;
418: nextChar = nChars;
419: }
420: }
421: return n - r;
422: }
423: }
424:
425: /**
426: * Tells whether this stream is ready to be read. A buffered character
427: * stream is ready if the buffer is not empty, or if the underlying
428: * character stream is ready.
429: *
430: * @exception IOException If an I/O error occurs
431: */
432: public boolean ready() throws IOException {
433: synchronized (lock) {
434: ensureOpen();
435:
436: /*
437: * If newline needs to be skipped and the next char to be read
438: * is a newline character, then just skip it right away.
439: */
440: if (skipLF) {
441: /* Note that in.ready() will return true if and only if the next
442: * read on the stream will not block.
443: */
444: if (nextChar >= nChars && in.ready()) {
445: fill();
446: }
447: if (nextChar < nChars) {
448: if (cb[nextChar] == '\n')
449: nextChar++;
450: skipLF = false;
451: }
452: }
453: return (nextChar < nChars) || in.ready();
454: }
455: }
456:
457: /**
458: * Tells whether this stream supports the mark() operation, which it does.
459: */
460: public boolean markSupported() {
461: return true;
462: }
463:
464: /**
465: * Marks the present position in the stream. Subsequent calls to reset()
466: * will attempt to reposition the stream to this point.
467: *
468: * @param readAheadLimit Limit on the number of characters that may be
469: * read while still preserving the mark. An attempt
470: * to reset the stream after reading characters
471: * up to this limit or beyond may fail.
472: * A limit value larger than the size of the input
473: * buffer will cause a new buffer to be allocated
474: * whose size is no smaller than limit.
475: * Therefore large values should be used with care.
476: *
477: * @exception IllegalArgumentException If readAheadLimit is < 0
478: * @exception IOException If an I/O error occurs
479: */
480: public void mark(int readAheadLimit) throws IOException {
481: if (readAheadLimit < 0) {
482: throw new IllegalArgumentException("Read-ahead limit < 0");
483: }
484: synchronized (lock) {
485: ensureOpen();
486: this .readAheadLimit = readAheadLimit;
487: markedChar = nextChar;
488: markedSkipLF = skipLF;
489: }
490: }
491:
492: /**
493: * Resets the stream to the most recent mark.
494: *
495: * @exception IOException If the stream has never been marked,
496: * or if the mark has been invalidated
497: */
498: public void reset() throws IOException {
499: synchronized (lock) {
500: ensureOpen();
501: if (markedChar < 0)
502: throw new IOException(
503: (markedChar == INVALIDATED) ? "Mark invalid"
504: : "Stream not marked");
505: nextChar = markedChar;
506: skipLF = markedSkipLF;
507: }
508: }
509:
510: public void close() throws IOException {
511: synchronized (lock) {
512: if (in == null)
513: return;
514: in.close();
515: in = null;
516: cb = null;
517: }
518: }
519: }
|