emul/compact/src/main/java/java/io/BufferedReader.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Wed, 23 Jan 2013 22:32:27 +0100
branchjdk7-b147
changeset 557 5be31d9fa455
child 560 53fafe384803
permissions -rw-r--r--
Basic classes needed to support ServiceLoader
     1 /*
     2  * Copyright (c) 1996, 2011, 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  * @see java.nio.file.Files#newBufferedReader
    58  *
    59  * @author      Mark Reinhold
    60  * @since       JDK1.1
    61  */
    62 
    63 public class BufferedReader extends Reader {
    64 
    65     private Reader in;
    66 
    67     private char cb[];
    68     private int nChars, nextChar;
    69 
    70     private static final int INVALIDATED = -2;
    71     private static final int UNMARKED = -1;
    72     private int markedChar = UNMARKED;
    73     private int readAheadLimit = 0; /* Valid only when markedChar > 0 */
    74 
    75     /** If the next character is a line feed, skip it */
    76     private boolean skipLF = false;
    77 
    78     /** The skipLF flag when the mark was set */
    79     private boolean markedSkipLF = false;
    80 
    81     private static int defaultCharBufferSize = 8192;
    82     private static int defaultExpectedLineLength = 80;
    83 
    84     /**
    85      * Creates a buffering character-input stream that uses an input buffer of
    86      * the specified size.
    87      *
    88      * @param  in   A Reader
    89      * @param  sz   Input-buffer size
    90      *
    91      * @exception  IllegalArgumentException  If sz is <= 0
    92      */
    93     public BufferedReader(Reader in, int sz) {
    94         super(in);
    95         if (sz <= 0)
    96             throw new IllegalArgumentException("Buffer size <= 0");
    97         this.in = in;
    98         cb = new char[sz];
    99         nextChar = nChars = 0;
   100     }
   101 
   102     /**
   103      * Creates a buffering character-input stream that uses a default-sized
   104      * input buffer.
   105      *
   106      * @param  in   A Reader
   107      */
   108     public BufferedReader(Reader in) {
   109         this(in, defaultCharBufferSize);
   110     }
   111 
   112     /** Checks to make sure that the stream has not been closed */
   113     private void ensureOpen() throws IOException {
   114         if (in == null)
   115             throw new IOException("Stream closed");
   116     }
   117 
   118     /**
   119      * Fills the input buffer, taking the mark into account if it is valid.
   120      */
   121     private void fill() throws IOException {
   122         int dst;
   123         if (markedChar <= UNMARKED) {
   124             /* No mark */
   125             dst = 0;
   126         } else {
   127             /* Marked */
   128             int delta = nextChar - markedChar;
   129             if (delta >= readAheadLimit) {
   130                 /* Gone past read-ahead limit: Invalidate mark */
   131                 markedChar = INVALIDATED;
   132                 readAheadLimit = 0;
   133                 dst = 0;
   134             } else {
   135                 if (readAheadLimit <= cb.length) {
   136                     /* Shuffle in the current buffer */
   137                     System.arraycopy(cb, markedChar, cb, 0, delta);
   138                     markedChar = 0;
   139                     dst = delta;
   140                 } else {
   141                     /* Reallocate buffer to accommodate read-ahead limit */
   142                     char ncb[] = new char[readAheadLimit];
   143                     System.arraycopy(cb, markedChar, ncb, 0, delta);
   144                     cb = ncb;
   145                     markedChar = 0;
   146                     dst = delta;
   147                 }
   148                 nextChar = nChars = delta;
   149             }
   150         }
   151 
   152         int n;
   153         do {
   154             n = in.read(cb, dst, cb.length - dst);
   155         } while (n == 0);
   156         if (n > 0) {
   157             nChars = dst + n;
   158             nextChar = dst;
   159         }
   160     }
   161 
   162     /**
   163      * Reads a single character.
   164      *
   165      * @return The character read, as an integer in the range
   166      *         0 to 65535 (<tt>0x00-0xffff</tt>), or -1 if the
   167      *         end of the stream has been reached
   168      * @exception  IOException  If an I/O error occurs
   169      */
   170     public int read() throws IOException {
   171         synchronized (lock) {
   172             ensureOpen();
   173             for (;;) {
   174                 if (nextChar >= nChars) {
   175                     fill();
   176                     if (nextChar >= nChars)
   177                         return -1;
   178                 }
   179                 if (skipLF) {
   180                     skipLF = false;
   181                     if (cb[nextChar] == '\n') {
   182                         nextChar++;
   183                         continue;
   184                     }
   185                 }
   186                 return cb[nextChar++];
   187             }
   188         }
   189     }
   190 
   191     /**
   192      * Reads characters into a portion of an array, reading from the underlying
   193      * stream if necessary.
   194      */
   195     private int read1(char[] cbuf, int off, int len) throws IOException {
   196         if (nextChar >= nChars) {
   197             /* If the requested length is at least as large as the buffer, and
   198                if there is no mark/reset activity, and if line feeds are not
   199                being skipped, do not bother to copy the characters into the
   200                local buffer.  In this way buffered streams will cascade
   201                harmlessly. */
   202             if (len >= cb.length && markedChar <= UNMARKED && !skipLF) {
   203                 return in.read(cbuf, off, len);
   204             }
   205             fill();
   206         }
   207         if (nextChar >= nChars) 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) return n;
   281             while ((n < len) && in.ready()) {
   282                 int n1 = read1(cbuf, off + n, len - n);
   283                 if (n1 <= 0) break;
   284                 n += n1;
   285             }
   286             return n;
   287         }
   288     }
   289 
   290     /**
   291      * Reads a line of text.  A line is considered to be terminated by any one
   292      * of a line feed ('\n'), a carriage return ('\r'), or a carriage return
   293      * followed immediately by a linefeed.
   294      *
   295      * @param      ignoreLF  If true, the next '\n' will be skipped
   296      *
   297      * @return     A String containing the contents of the line, not including
   298      *             any line-termination characters, or null if the end of the
   299      *             stream has been reached
   300      *
   301      * @see        java.io.LineNumberReader#readLine()
   302      *
   303      * @exception  IOException  If an I/O error occurs
   304      */
   305     String readLine(boolean ignoreLF) throws IOException {
   306         StringBuffer s = null;
   307         int startChar;
   308 
   309         synchronized (lock) {
   310             ensureOpen();
   311             boolean omitLF = ignoreLF || skipLF;
   312 
   313         bufferLoop:
   314             for (;;) {
   315 
   316                 if (nextChar >= nChars)
   317                     fill();
   318                 if (nextChar >= nChars) { /* EOF */
   319                     if (s != null && s.length() > 0)
   320                         return s.toString();
   321                     else
   322                         return null;
   323                 }
   324                 boolean eol = false;
   325                 char c = 0;
   326                 int i;
   327 
   328                 /* Skip a leftover '\n', if necessary */
   329                 if (omitLF && (cb[nextChar] == '\n'))
   330                     nextChar++;
   331                 skipLF = false;
   332                 omitLF = false;
   333 
   334             charLoop:
   335                 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      * @see java.nio.file.Files#readAllLines
   380      */
   381     public String readLine() throws IOException {
   382         return readLine(false);
   383     }
   384 
   385     /**
   386      * Skips characters.
   387      *
   388      * @param  n  The number of characters to skip
   389      *
   390      * @return    The number of characters actually skipped
   391      *
   392      * @exception  IllegalArgumentException  If <code>n</code> is negative.
   393      * @exception  IOException  If an I/O error occurs
   394      */
   395     public long skip(long n) throws IOException {
   396         if (n < 0L) {
   397             throw new IllegalArgumentException("skip value is negative");
   398         }
   399         synchronized (lock) {
   400             ensureOpen();
   401             long r = n;
   402             while (r > 0) {
   403                 if (nextChar >= nChars)
   404                     fill();
   405                 if (nextChar >= nChars) /* EOF */
   406                     break;
   407                 if (skipLF) {
   408                     skipLF = false;
   409                     if (cb[nextChar] == '\n') {
   410                         nextChar++;
   411                     }
   412                 }
   413                 long d = nChars - nextChar;
   414                 if (r <= d) {
   415                     nextChar += r;
   416                     r = 0;
   417                     break;
   418                 }
   419                 else {
   420                     r -= d;
   421                     nextChar = nChars;
   422                 }
   423             }
   424             return n - r;
   425         }
   426     }
   427 
   428     /**
   429      * Tells whether this stream is ready to be read.  A buffered character
   430      * stream is ready if the buffer is not empty, or if the underlying
   431      * character stream is ready.
   432      *
   433      * @exception  IOException  If an I/O error occurs
   434      */
   435     public boolean ready() throws IOException {
   436         synchronized (lock) {
   437             ensureOpen();
   438 
   439             /*
   440              * If newline needs to be skipped and the next char to be read
   441              * is a newline character, then just skip it right away.
   442              */
   443             if (skipLF) {
   444                 /* Note that in.ready() will return true if and only if the next
   445                  * read on the stream will not block.
   446                  */
   447                 if (nextChar >= nChars && in.ready()) {
   448                     fill();
   449                 }
   450                 if (nextChar < nChars) {
   451                     if (cb[nextChar] == '\n')
   452                         nextChar++;
   453                     skipLF = false;
   454                 }
   455             }
   456             return (nextChar < nChars) || in.ready();
   457         }
   458     }
   459 
   460     /**
   461      * Tells whether this stream supports the mark() operation, which it does.
   462      */
   463     public boolean markSupported() {
   464         return true;
   465     }
   466 
   467     /**
   468      * Marks the present position in the stream.  Subsequent calls to reset()
   469      * will attempt to reposition the stream to this point.
   470      *
   471      * @param readAheadLimit   Limit on the number of characters that may be
   472      *                         read while still preserving the mark. An attempt
   473      *                         to reset the stream after reading characters
   474      *                         up to this limit or beyond may fail.
   475      *                         A limit value larger than the size of the input
   476      *                         buffer will cause a new buffer to be allocated
   477      *                         whose size is no smaller than limit.
   478      *                         Therefore large values should be used with care.
   479      *
   480      * @exception  IllegalArgumentException  If readAheadLimit is < 0
   481      * @exception  IOException  If an I/O error occurs
   482      */
   483     public void mark(int readAheadLimit) throws IOException {
   484         if (readAheadLimit < 0) {
   485             throw new IllegalArgumentException("Read-ahead limit < 0");
   486         }
   487         synchronized (lock) {
   488             ensureOpen();
   489             this.readAheadLimit = readAheadLimit;
   490             markedChar = nextChar;
   491             markedSkipLF = skipLF;
   492         }
   493     }
   494 
   495     /**
   496      * Resets the stream to the most recent mark.
   497      *
   498      * @exception  IOException  If the stream has never been marked,
   499      *                          or if the mark has been invalidated
   500      */
   501     public void reset() throws IOException {
   502         synchronized (lock) {
   503             ensureOpen();
   504             if (markedChar < 0)
   505                 throw new IOException((markedChar == INVALIDATED)
   506                                       ? "Mark invalid"
   507                                       : "Stream not marked");
   508             nextChar = markedChar;
   509             skipLF = markedSkipLF;
   510         }
   511     }
   512 
   513     public void close() throws IOException {
   514         synchronized (lock) {
   515             if (in == null)
   516                 return;
   517             in.close();
   518             in = null;
   519             cb = null;
   520         }
   521     }
   522 }