KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > io > BufferedReader


1 /*
2  * @(#)BufferedReader.java 1.33 04/01/12
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package java.io;
9
10
11 /**
12  * Read text from a character-input stream, buffering characters so as to
13  * provide for the efficient reading of characters, arrays, and lines.
14  *
15  * <p> The buffer size may be specified, or the default size may be used. The
16  * default is large enough for most purposes.
17  *
18  * <p> In general, each read request made of a Reader causes a corresponding
19  * read request to be made of the underlying character or byte stream. It is
20  * therefore advisable to wrap a BufferedReader around any Reader whose read()
21  * operations may be costly, such as FileReaders and InputStreamReaders. For
22  * example,
23  *
24  * <pre>
25  * BufferedReader in
26  * = new BufferedReader(new FileReader("foo.in"));
27  * </pre>
28  *
29  * will buffer the input from the specified file. Without buffering, each
30  * invocation of read() or readLine() could cause bytes to be read from the
31  * file, converted into characters, and then returned, which can be very
32  * inefficient.
33  *
34  * <p> Programs that use DataInputStreams for textual input can be localized by
35  * replacing each DataInputStream with an appropriate BufferedReader.
36  *
37  * @see FileReader
38  * @see InputStreamReader
39  *
40  * @version 1.33, 04/01/12
41  * @author Mark Reinhold
42  * @since JDK1.1
43  */

44
45 public class BufferedReader extends Reader JavaDoc {
46
47     private Reader JavaDoc in;
48
49     private char cb[];
50     private int nChars, nextChar;
51
52     private static final int INVALIDATED = -2;
53     private static final int UNMARKED = -1;
54     private int markedChar = UNMARKED;
55     private int readAheadLimit = 0; /* Valid only when markedChar > 0 */
56
57     /** If the next character is a line feed, skip it */
58     private boolean skipLF = false;
59
60     /** The skipLF flag when the mark was set */
61     private boolean markedSkipLF = false;
62
63     private static int defaultCharBufferSize = 8192;
64     private static int defaultExpectedLineLength = 80;
65
66     /**
67      * Create a buffering character-input stream that uses an input buffer of
68      * the specified size.
69      *
70      * @param in A Reader
71      * @param sz Input-buffer size
72      *
73      * @exception IllegalArgumentException If sz is <= 0
74      */

75     public BufferedReader(Reader JavaDoc in, int sz) {
76     super(in);
77     if (sz <= 0)
78         throw new IllegalArgumentException JavaDoc("Buffer size <= 0");
79     this.in = in;
80     cb = new char[sz];
81     nextChar = nChars = 0;
82     }
83
84     /**
85      * Create a buffering character-input stream that uses a default-sized
86      * input buffer.
87      *
88      * @param in A Reader
89      */

90     public BufferedReader(Reader JavaDoc in) {
91     this(in, defaultCharBufferSize);
92     }
93
94     /** Check to make sure that the stream has not been closed */
95     private void ensureOpen() throws IOException JavaDoc {
96     if (in == null)
97         throw new IOException JavaDoc("Stream closed");
98     }
99
100     /**
101      * Fill the input buffer, taking the mark into account if it is valid.
102      */

103     private void fill() throws IOException JavaDoc {
104     int dst;
105     if (markedChar <= UNMARKED) {
106         /* No mark */
107         dst = 0;
108     } else {
109         /* Marked */
110         int delta = nextChar - markedChar;
111         if (delta >= readAheadLimit) {
112         /* Gone past read-ahead limit: Invalidate mark */
113         markedChar = INVALIDATED;
114         readAheadLimit = 0;
115         dst = 0;
116         } else {
117         if (readAheadLimit <= cb.length) {
118             /* Shuffle in the current buffer */
119             System.arraycopy(cb, markedChar, cb, 0, delta);
120             markedChar = 0;
121             dst = delta;
122         } else {
123             /* Reallocate buffer to accommodate read-ahead limit */
124             char ncb[] = new char[readAheadLimit];
125             System.arraycopy(cb, markedChar, ncb, 0, delta);
126             cb = ncb;
127             markedChar = 0;
128             dst = delta;
129         }
130                 nextChar = nChars = delta;
131         }
132     }
133
134     int n;
135     do {
136         n = in.read(cb, dst, cb.length - dst);
137     } while (n == 0);
138     if (n > 0) {
139         nChars = dst + n;
140         nextChar = dst;
141     }
142     }
143
144     /**
145      * Read a single character.
146      *
147      * @return The character read, as an integer in the range
148      * 0 to 65535 (<tt>0x00-0xffff</tt>), or -1 if the
149      * end of the stream has been reached
150      * @exception IOException If an I/O error occurs
151      */

152     public int read() throws IOException JavaDoc {
153     synchronized (lock) {
154         ensureOpen();
155         for (;;) {
156         if (nextChar >= nChars) {
157             fill();
158             if (nextChar >= nChars)
159             return -1;
160         }
161         if (skipLF) {
162             skipLF = false;
163             if (cb[nextChar] == '\n') {
164             nextChar++;
165             continue;
166             }
167         }
168         return cb[nextChar++];
169         }
170     }
171     }
172
173     /**
174      * Read characters into a portion of an array, reading from the underlying
175      * stream if necessary.
176      */

177     private int read1(char[] cbuf, int off, int len) throws IOException JavaDoc {
178     if (nextChar >= nChars) {
179         /* If the requested length is at least as large as the buffer, and
180            if there is no mark/reset activity, and if line feeds are not
181            being skipped, do not bother to copy the characters into the
182            local buffer. In this way buffered streams will cascade
183            harmlessly. */

184         if (len >= cb.length && markedChar <= UNMARKED && !skipLF) {
185         return in.read(cbuf, off, len);
186         }
187         fill();
188     }
189     if (nextChar >= nChars) return -1;
190     if (skipLF) {
191         skipLF = false;
192         if (cb[nextChar] == '\n') {
193         nextChar++;
194         if (nextChar >= nChars)
195             fill();
196         if (nextChar >= nChars)
197             return -1;
198         }
199     }
200     int n = Math.min(len, nChars - nextChar);
201     System.arraycopy(cb, nextChar, cbuf, off, n);
202     nextChar += n;
203     return n;
204     }
205
206     /**
207      * Read characters into a portion of an array.
208      *
209      * <p> This method implements the general contract of the corresponding
210      * <code>{@link Reader#read(char[], int, int) read}</code> method of the
211      * <code>{@link Reader}</code> class. As an additional convenience, it
212      * attempts to read as many characters as possible by repeatedly invoking
213      * the <code>read</code> method of the underlying stream. This iterated
214      * <code>read</code> continues until one of the following conditions becomes
215      * true: <ul>
216      *
217      * <li> The specified number of characters have been read,
218      *
219      * <li> The <code>read</code> method of the underlying stream returns
220      * <code>-1</code>, indicating end-of-file, or
221      *
222      * <li> The <code>ready</code> method of the underlying stream
223      * returns <code>false</code>, indicating that further input requests
224      * would block.
225      *
226      * </ul> If the first <code>read</code> on the underlying stream returns
227      * <code>-1</code> to indicate end-of-file then this method returns
228      * <code>-1</code>. Otherwise this method returns the number of characters
229      * actually read.
230      *
231      * <p> Subclasses of this class are encouraged, but not required, to
232      * attempt to read as many characters as possible in the same fashion.
233      *
234      * <p> Ordinarily this method takes characters from this stream's character
235      * buffer, filling it from the underlying stream as necessary. If,
236      * however, the buffer is empty, the mark is not valid, and the requested
237      * length is at least as large as the buffer, then this method will read
238      * characters directly from the underlying stream into the given array.
239      * Thus redundant <code>BufferedReader</code>s will not copy data
240      * unnecessarily.
241      *
242      * @param cbuf Destination buffer
243      * @param off Offset at which to start storing characters
244      * @param len Maximum number of characters to read
245      *
246      * @return The number of characters read, or -1 if the end of the
247      * stream has been reached
248      *
249      * @exception IOException If an I/O error occurs
250      */

251     public int read(char cbuf[], int off, int len) throws IOException JavaDoc {
252         synchronized (lock) {
253         ensureOpen();
254             if ((off < 0) || (off > cbuf.length) || (len < 0) ||
255                 ((off + len) > cbuf.length) || ((off + len) < 0)) {
256                 throw new IndexOutOfBoundsException JavaDoc();
257             } else if (len == 0) {
258                 return 0;
259             }
260
261         int n = read1(cbuf, off, len);
262         if (n <= 0) return n;
263         while ((n < len) && in.ready()) {
264         int n1 = read1(cbuf, off + n, len - n);
265         if (n1 <= 0) break;
266         n += n1;
267         }
268         return n;
269     }
270     }
271
272     /**
273      * Read a line of text. A line is considered to be terminated by any one
274      * of a line feed ('\n'), a carriage return ('\r'), or a carriage return
275      * followed immediately by a linefeed.
276      *
277      * @param ignoreLF If true, the next '\n' will be skipped
278      *
279      * @return A String containing the contents of the line, not including
280      * any line-termination characters, or null if the end of the
281      * stream has been reached
282      *
283      * @see java.io.LineNumberReader#readLine()
284      *
285      * @exception IOException If an I/O error occurs
286      */

287     String JavaDoc readLine(boolean ignoreLF) throws IOException JavaDoc {
288     StringBuffer JavaDoc s = null;
289     int startChar;
290     boolean omitLF = ignoreLF || skipLF;
291
292         synchronized (lock) {
293             ensureOpen();
294
295     bufferLoop:
296         for (;;) {
297
298         if (nextChar >= nChars)
299             fill();
300         if (nextChar >= nChars) { /* EOF */
301             if (s != null && s.length() > 0)
302             return s.toString();
303             else
304             return null;
305         }
306         boolean eol = false;
307         char c = 0;
308         int i;
309
310                 /* Skip a leftover '\n', if necessary */
311         if (omitLF && (cb[nextChar] == '\n'))
312                     nextChar++;
313         skipLF = false;
314         omitLF = false;
315
316         charLoop:
317         for (i = nextChar; i < nChars; i++) {
318             c = cb[i];
319             if ((c == '\n') || (c == '\r')) {
320             eol = true;
321             break charLoop;
322             }
323         }
324
325         startChar = nextChar;
326         nextChar = i;
327
328         if (eol) {
329             String JavaDoc str;
330             if (s == null) {
331             str = new String JavaDoc(cb, startChar, i - startChar);
332             } else {
333             s.append(cb, startChar, i - startChar);
334             str = s.toString();
335             }
336             nextChar++;
337             if (c == '\r') {
338             skipLF = true;
339             }
340             return str;
341         }
342         
343         if (s == null)
344             s = new StringBuffer JavaDoc(defaultExpectedLineLength);
345         s.append(cb, startChar, i - startChar);
346         }
347         }
348     }
349
350     /**
351      * Read a line of text. A line is considered to be terminated by any one
352      * of a line feed ('\n'), a carriage return ('\r'), or a carriage return
353      * followed immediately by a linefeed.
354      *
355      * @return A String containing the contents of the line, not including
356      * any line-termination characters, or null if the end of the
357      * stream has been reached
358      *
359      * @exception IOException If an I/O error occurs
360      */

361     public String JavaDoc readLine() throws IOException JavaDoc {
362         return readLine(false);
363     }
364
365     /**
366      * Skip characters.
367      *
368      * @param n The number of characters to skip
369      *
370      * @return The number of characters actually skipped
371      *
372      * @exception IllegalArgumentException If <code>n</code> is negative.
373      * @exception IOException If an I/O error occurs
374      */

375     public long skip(long n) throws IOException JavaDoc {
376     if (n < 0L) {
377         throw new IllegalArgumentException JavaDoc("skip value is negative");
378     }
379     synchronized (lock) {
380         ensureOpen();
381         long r = n;
382         while (r > 0) {
383         if (nextChar >= nChars)
384             fill();
385         if (nextChar >= nChars) /* EOF */
386             break;
387         if (skipLF) {
388             skipLF = false;
389             if (cb[nextChar] == '\n') {
390             nextChar++;
391             }
392         }
393         long d = nChars - nextChar;
394         if (r <= d) {
395             nextChar += r;
396             r = 0;
397             break;
398         }
399         else {
400             r -= d;
401             nextChar = nChars;
402         }
403         }
404         return n - r;
405     }
406     }
407
408     /**
409      * Tell whether this stream is ready to be read. A buffered character
410      * stream is ready if the buffer is not empty, or if the underlying
411      * character stream is ready.
412      *
413      * @exception IOException If an I/O error occurs
414      */

415     public boolean ready() throws IOException JavaDoc {
416     synchronized (lock) {
417         ensureOpen();
418
419         /*
420          * If newline needs to be skipped and the next char to be read
421          * is a newline character, then just skip it right away.
422          */

423         if (skipLF) {
424         /* Note that in.ready() will return true if and only if the next
425          * read on the stream will not block.
426          */

427         if (nextChar >= nChars && in.ready()) {
428             fill();
429         }
430         if (nextChar < nChars) {
431             if (cb[nextChar] == '\n')
432             nextChar++;
433             skipLF = false;
434         }
435         }
436         return (nextChar < nChars) || in.ready();
437     }
438     }
439
440     /**
441      * Tell whether this stream supports the mark() operation, which it does.
442      */

443     public boolean markSupported() {
444     return true;
445     }
446
447     /**
448      * Mark the present position in the stream. Subsequent calls to reset()
449      * will attempt to reposition the stream to this point.
450      *
451      * @param readAheadLimit Limit on the number of characters that may be
452      * read while still preserving the mark. After
453      * reading this many characters, attempting to
454      * reset the stream may fail. A limit value larger
455      * than the size of the input buffer will cause a
456      * new buffer to be allocated whose size is no
457      * smaller than limit. Therefore large values
458      * should be used with care.
459      *
460      * @exception IllegalArgumentException If readAheadLimit is < 0
461      * @exception IOException If an I/O error occurs
462      */

463     public void mark(int readAheadLimit) throws IOException JavaDoc {
464     if (readAheadLimit < 0) {
465         throw new IllegalArgumentException JavaDoc("Read-ahead limit < 0");
466     }
467     synchronized (lock) {
468         ensureOpen();
469         this.readAheadLimit = readAheadLimit;
470         markedChar = nextChar;
471         markedSkipLF = skipLF;
472     }
473     }
474
475     /**
476      * Reset the stream to the most recent mark.
477      *
478      * @exception IOException If the stream has never been marked,
479      * or if the mark has been invalidated
480      */

481     public void reset() throws IOException JavaDoc {
482     synchronized (lock) {
483         ensureOpen();
484         if (markedChar < 0)
485         throw new IOException JavaDoc((markedChar == INVALIDATED)
486                       ? "Mark invalid"
487                       : "Stream not marked");
488         nextChar = markedChar;
489         skipLF = markedSkipLF;
490     }
491     }
492
493     /**
494      * Close the stream.
495      *
496      * @exception IOException If an I/O error occurs
497      */

498     public void close() throws IOException JavaDoc {
499     synchronized (lock) {
500         if (in == null)
501         return;
502         in.close();
503         in = null;
504         cb = null;
505     }
506     }
507
508 }
509
Popular Tags