1 /* 2 * Copyright (c) 1996, 2006, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * 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 }