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 }
|