1 /*
2 * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26 package java.io;
27
28
29 /**
30 * Reads text from a character-input stream, buffering characters so as to
31 * provide for the efficient reading of characters, arrays, and lines.
32 *
33 * <p> The buffer size may be specified, or the default size may be used. The
34 * default is large enough for most purposes.
35 *
36 * <p> In general, each read request made of a Reader causes a corresponding
37 * read request to be made of the underlying character or byte stream. It is
38 * therefore advisable to wrap a BufferedReader around any Reader whose read()
39 * operations may be costly, such as FileReaders and InputStreamReaders. For
40 * example,
41 *
42 * <pre>
43 * BufferedReader in
44 * = new BufferedReader(new FileReader("foo.in"));
45 * </pre>
46 *
47 * will buffer the input from the specified file. Without buffering, each
48 * invocation of read() or readLine() could cause bytes to be read from the
49 * file, converted into characters, and then returned, which can be very
50 * inefficient.
51 *
52 * <p> Programs that use DataInputStreams for textual input can be localized by
53 * replacing each DataInputStream with an appropriate BufferedReader.
54 *
55 * @see FileReader
56 * @see InputStreamReader
57 *
58 * @author Mark Reinhold
59 * @since JDK1.1
60 */
61
62 public class BufferedReader extends Reader {
63
64 private Reader in;
65
66 private char cb[];
67 private int nChars, nextChar;
68
69 private static final int INVALIDATED = -2;
70 private static final int UNMARKED = -1;
71 private int markedChar = UNMARKED;
72 private int readAheadLimit = 0; /* Valid only when markedChar > 0 */
73
74 /** If the next character is a line feed, skip it */
75 private boolean skipLF = false;
76
77 /** The skipLF flag when the mark was set */
78 private boolean markedSkipLF = false;
79
80 private static int defaultCharBufferSize = 8192;
81 private static int defaultExpectedLineLength = 80;
82
83 /**
84 * Creates a buffering character-input stream that uses an input buffer of
85 * the specified size.
86 *
87 * @param in A Reader
88 * @param sz Input-buffer size
89 *
90 * @exception IllegalArgumentException If sz is <= 0
91 */
92 public BufferedReader(Reader in, int sz) {
93 super(in);
94 if (sz <= 0)
95 throw new IllegalArgumentException("Buffer size <= 0");
96 this.in = in;
97 cb = new char[sz];
98 nextChar = nChars = 0;
99 }
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) return -1;
207 if (skipLF) {
208 skipLF = false;
209 if (cb[nextChar] == '\n') {
210 nextChar++;
211 if (nextChar >= nChars)
212 fill();
213 if (nextChar >= nChars)
214 return -1;
215 }
216 }
217 int n = Math.min(len, nChars - nextChar);
218 System.arraycopy(cb, nextChar, cbuf, off, n);
219 nextChar += n;
220 return n;
221 }
222
223 /**
224 * Reads characters into a portion of an array.
225 *
226 * <p> This method implements the general contract of the corresponding
227 * <code>{@link Reader#read(char[], int, int) read}</code> method of the
228 * <code>{@link Reader}</code> class. As an additional convenience, it
229 * attempts to read as many characters as possible by repeatedly invoking
230 * the <code>read</code> method of the underlying stream. This iterated
231 * <code>read</code> continues until one of the following conditions becomes
232 * true: <ul>
233 *
234 * <li> The specified number of characters have been read,
235 *
236 * <li> The <code>read</code> method of the underlying stream returns
237 * <code>-1</code>, indicating end-of-file, or
238 *
239 * <li> The <code>ready</code> method of the underlying stream
240 * returns <code>false</code>, indicating that further input requests
241 * would block.
242 *
243 * </ul> If the first <code>read</code> on the underlying stream returns
244 * <code>-1</code> to indicate end-of-file then this method returns
245 * <code>-1</code>. Otherwise this method returns the number of characters
246 * actually read.
247 *
248 * <p> Subclasses of this class are encouraged, but not required, to
249 * attempt to read as many characters as possible in the same fashion.
250 *
251 * <p> Ordinarily this method takes characters from this stream's character
252 * buffer, filling it from the underlying stream as necessary. If,
253 * however, the buffer is empty, the mark is not valid, and the requested
254 * length is at least as large as the buffer, then this method will read
255 * characters directly from the underlying stream into the given array.
256 * Thus redundant <code>BufferedReader</code>s will not copy data
257 * unnecessarily.
258 *
259 * @param cbuf Destination buffer
260 * @param off Offset at which to start storing characters
261 * @param len Maximum number of characters to read
262 *
263 * @return The number of characters read, or -1 if the end of the
264 * stream has been reached
265 *
266 * @exception IOException If an I/O error occurs
267 */
268 public int read(char cbuf[], int off, int len) throws IOException {
269 synchronized (lock) {
270 ensureOpen();
271 if ((off < 0) || (off > cbuf.length) || (len < 0) ||
272 ((off + len) > cbuf.length) || ((off + len) < 0)) {
273 throw new IndexOutOfBoundsException();
274 } else if (len == 0) {
275 return 0;
276 }
277
278 int n = read1(cbuf, off, len);
279 if (n <= 0) return n;
280 while ((n < len) && in.ready()) {
281 int n1 = read1(cbuf, off + n, len - n);
282 if (n1 <= 0) break;
283 n += n1;
284 }
285 return n;
286 }
287 }
288
289 /**
290 * Reads a line of text. A line is considered to be terminated by any one
291 * of a line feed ('\n'), a carriage return ('\r'), or a carriage return
292 * followed immediately by a linefeed.
293 *
294 * @param ignoreLF If true, the next '\n' will be skipped
295 *
296 * @return A String containing the contents of the line, not including
297 * any line-termination characters, or null if the end of the
298 * stream has been reached
299 *
300 * @see java.io.LineNumberReader#readLine()
301 *
302 * @exception IOException If an I/O error occurs
303 */
304 String readLine(boolean ignoreLF) throws IOException {
305 StringBuffer s = null;
306 int startChar;
307
308 synchronized (lock) {
309 ensureOpen();
310 boolean omitLF = ignoreLF || skipLF;
311
312 bufferLoop:
313 for (;;) {
314
315 if (nextChar >= nChars)
316 fill();
317 if (nextChar >= nChars) { /* EOF */
318 if (s != null && s.length() > 0)
319 return s.toString();
320 else
321 return null;
322 }
323 boolean eol = false;
324 char c = 0;
325 int i;
326
327 /* Skip a leftover '\n', if necessary */
328 if (omitLF && (cb[nextChar] == '\n'))
329 nextChar++;
330 skipLF = false;
331 omitLF = false;
332
333 charLoop:
334 for (i = nextChar; i < nChars; i++) {
335 c = cb[i];
336 if ((c == '\n') || (c == '\r')) {
337 eol = true;
338 break charLoop;
339 }
340 }
341
342 startChar = nextChar;
343 nextChar = i;
344
345 if (eol) {
346 String str;
347 if (s == null) {
348 str = new String(cb, startChar, i - startChar);
349 } else {
350 s.append(cb, startChar, i - startChar);
351 str = s.toString();
352 }
353 nextChar++;
354 if (c == '\r') {
355 skipLF = true;
356 }
357 return str;
358 }
359
360 if (s == null)
361 s = new StringBuffer(defaultExpectedLineLength);
362 s.append(cb, startChar, i - startChar);
363 }
364 }
365 }
366
367 /**
368 * Reads a line of text. A line is considered to be terminated by any one
369 * of a line feed ('\n'), a carriage return ('\r'), or a carriage return
370 * followed immediately by a linefeed.
371 *
372 * @return A String containing the contents of the line, not including
373 * any line-termination characters, or null if the end of the
374 * stream has been reached
375 *
376 * @exception IOException If an I/O error occurs
377 */
378 public String readLine() throws IOException {
379 return readLine(false);
380 }
381
382 /**
383 * Skips characters.
384 *
385 * @param n The number of characters to skip
386 *
387 * @return The number of characters actually skipped
388 *
389 * @exception IllegalArgumentException If <code>n</code> is negative.
390 * @exception IOException If an I/O error occurs
391 */
392 public long skip(long n) throws IOException {
393 if (n < 0L) {
394 throw new IllegalArgumentException("skip value is negative");
395 }
396 synchronized (lock) {
397 ensureOpen();
398 long r = n;
399 while (r > 0) {
400 if (nextChar >= nChars)
401 fill();
402 if (nextChar >= nChars) /* EOF */
403 break;
404 if (skipLF) {
405 skipLF = false;
406 if (cb[nextChar] == '\n') {
407 nextChar++;
408 }
409 }
410 long d = nChars - nextChar;
411 if (r <= d) {
412 nextChar += r;
413 r = 0;
414 break;
415 }
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((markedChar == INVALIDATED)
503 ? "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 }