rt/emul/compact/src/main/java/java/io/BufferedReader.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Tue, 26 Feb 2013 16:54:16 +0100
changeset 772 d382dacfd73f
parent 636 emul/compact/src/main/java/java/io/BufferedReader.java@8d0be6a9a809
permissions -rw-r--r--
Moving modules around so the runtime is under one master pom and can be built without building other modules that are in the repository
     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 /**
    31  * Reads text from a character-input stream, buffering characters so as to
    32  * provide for the efficient reading of characters, arrays, and lines.
    33  *
    34  * <p> The buffer size may be specified, or the default size may be used.  The
    35  * default is large enough for most purposes.
    36  *
    37  * <p> In general, each read request made of a Reader causes a corresponding
    38  * read request to be made of the underlying character or byte stream.  It is
    39  * therefore advisable to wrap a BufferedReader around any Reader whose read()
    40  * operations may be costly, such as FileReaders and InputStreamReaders.  For
    41  * example,
    42  *
    43  * <pre>
    44  * BufferedReader in
    45  *   = new BufferedReader(new FileReader("foo.in"));
    46  * </pre>
    47  *
    48  * will buffer the input from the specified file.  Without buffering, each
    49  * invocation of read() or readLine() could cause bytes to be read from the
    50  * file, converted into characters, and then returned, which can be very
    51  * inefficient.
    52  *
    53  * <p> Programs that use DataInputStreams for textual input can be localized by
    54  * replacing each DataInputStream with an appropriate BufferedReader.
    55  *
    56  * @see FileReader
    57  * @see InputStreamReader
    58  * @see java.nio.file.Files#newBufferedReader
    59  *
    60  * @author      Mark Reinhold
    61  * @since       JDK1.1
    62  */
    63 
    64 public class BufferedReader extends Reader {
    65 
    66     private Reader in;
    67 
    68     private char cb[];
    69     private int nChars, nextChar;
    70 
    71     private static final int INVALIDATED = -2;
    72     private static final int UNMARKED = -1;
    73     private int markedChar = UNMARKED;
    74     private int readAheadLimit = 0; /* Valid only when markedChar > 0 */
    75 
    76     /** If the next character is a line feed, skip it */
    77     private boolean skipLF = false;
    78 
    79     /** The skipLF flag when the mark was set */
    80     private boolean markedSkipLF = false;
    81 
    82     private static int defaultCharBufferSize = 8192;
    83     private static int defaultExpectedLineLength = 80;
    84 
    85     /**
    86      * Creates a buffering character-input stream that uses an input buffer of
    87      * the specified size.
    88      *
    89      * @param  in   A Reader
    90      * @param  sz   Input-buffer size
    91      *
    92      * @exception  IllegalArgumentException  If sz is <= 0
    93      */
    94     public BufferedReader(Reader in, int sz) {
    95         super(in);
    96         if (sz <= 0)
    97             throw new IllegalArgumentException("Buffer size <= 0");
    98         this.in = in;
    99         cb = new char[sz];
   100         nextChar = nChars = 0;
   101     }
   102 
   103     /**
   104      * Creates a buffering character-input stream that uses a default-sized
   105      * input buffer.
   106      *
   107      * @param  in   A Reader
   108      */
   109     public BufferedReader(Reader in) {
   110         this(in, defaultCharBufferSize);
   111     }
   112 
   113     /** Checks to make sure that the stream has not been closed */
   114     private void ensureOpen() throws IOException {
   115         if (in == null)
   116             throw new IOException("Stream closed");
   117     }
   118 
   119     /**
   120      * Fills the input buffer, taking the mark into account if it is valid.
   121      */
   122     private void fill() throws IOException {
   123         int dst;
   124         if (markedChar <= UNMARKED) {
   125             /* No mark */
   126             dst = 0;
   127         } else {
   128             /* Marked */
   129             int delta = nextChar - markedChar;
   130             if (delta >= readAheadLimit) {
   131                 /* Gone past read-ahead limit: Invalidate mark */
   132                 markedChar = INVALIDATED;
   133                 readAheadLimit = 0;
   134                 dst = 0;
   135             } else {
   136                 if (readAheadLimit <= cb.length) {
   137                     /* Shuffle in the current buffer */
   138                     System.arraycopy(cb, markedChar, cb, 0, delta);
   139                     markedChar = 0;
   140                     dst = delta;
   141                 } else {
   142                     /* Reallocate buffer to accommodate read-ahead limit */
   143                     char ncb[] = new char[readAheadLimit];
   144                     System.arraycopy(cb, markedChar, ncb, 0, delta);
   145                     cb = ncb;
   146                     markedChar = 0;
   147                     dst = delta;
   148                 }
   149                 nextChar = nChars = delta;
   150             }
   151         }
   152 
   153         int n;
   154         do {
   155             n = in.read(cb, dst, cb.length - dst);
   156         } while (n == 0);
   157         if (n > 0) {
   158             nChars = dst + n;
   159             nextChar = dst;
   160         }
   161     }
   162 
   163     /**
   164      * Reads a single character.
   165      *
   166      * @return The character read, as an integer in the range
   167      *         0 to 65535 (<tt>0x00-0xffff</tt>), or -1 if the
   168      *         end of the stream has been reached
   169      * @exception  IOException  If an I/O error occurs
   170      */
   171     public int read() throws IOException {
   172         synchronized (lock) {
   173             ensureOpen();
   174             for (;;) {
   175                 if (nextChar >= nChars) {
   176                     fill();
   177                     if (nextChar >= nChars)
   178                         return -1;
   179                 }
   180                 if (skipLF) {
   181                     skipLF = false;
   182                     if (cb[nextChar] == '\n') {
   183                         nextChar++;
   184                         continue;
   185                     }
   186                 }
   187                 return cb[nextChar++];
   188             }
   189         }
   190     }
   191 
   192     /**
   193      * Reads characters into a portion of an array, reading from the underlying
   194      * stream if necessary.
   195      */
   196     private int read1(char[] cbuf, int off, int len) throws IOException {
   197         if (nextChar >= nChars) {
   198             /* If the requested length is at least as large as the buffer, and
   199                if there is no mark/reset activity, and if line feeds are not
   200                being skipped, do not bother to copy the characters into the
   201                local buffer.  In this way buffered streams will cascade
   202                harmlessly. */
   203             if (len >= cb.length && markedChar <= UNMARKED && !skipLF) {
   204                 return in.read(cbuf, off, len);
   205             }
   206             fill();
   207         }
   208         if (nextChar >= nChars) return -1;
   209         if (skipLF) {
   210             skipLF = false;
   211             if (cb[nextChar] == '\n') {
   212                 nextChar++;
   213                 if (nextChar >= nChars)
   214                     fill();
   215                 if (nextChar >= nChars)
   216                     return -1;
   217             }
   218         }
   219         int n = Math.min(len, nChars - nextChar);
   220         System.arraycopy(cb, nextChar, cbuf, off, n);
   221         nextChar += n;
   222         return n;
   223     }
   224 
   225     /**
   226      * Reads characters into a portion of an array.
   227      *
   228      * <p> This method implements the general contract of the corresponding
   229      * <code>{@link Reader#read(char[], int, int) read}</code> method of the
   230      * <code>{@link Reader}</code> class.  As an additional convenience, it
   231      * attempts to read as many characters as possible by repeatedly invoking
   232      * the <code>read</code> method of the underlying stream.  This iterated
   233      * <code>read</code> continues until one of the following conditions becomes
   234      * true: <ul>
   235      *
   236      *   <li> The specified number of characters have been read,
   237      *
   238      *   <li> The <code>read</code> method of the underlying stream returns
   239      *   <code>-1</code>, indicating end-of-file, or
   240      *
   241      *   <li> The <code>ready</code> method of the underlying stream
   242      *   returns <code>false</code>, indicating that further input requests
   243      *   would block.
   244      *
   245      * </ul> If the first <code>read</code> on the underlying stream returns
   246      * <code>-1</code> to indicate end-of-file then this method returns
   247      * <code>-1</code>.  Otherwise this method returns the number of characters
   248      * actually read.
   249      *
   250      * <p> Subclasses of this class are encouraged, but not required, to
   251      * attempt to read as many characters as possible in the same fashion.
   252      *
   253      * <p> Ordinarily this method takes characters from this stream's character
   254      * buffer, filling it from the underlying stream as necessary.  If,
   255      * however, the buffer is empty, the mark is not valid, and the requested
   256      * length is at least as large as the buffer, then this method will read
   257      * characters directly from the underlying stream into the given array.
   258      * Thus redundant <code>BufferedReader</code>s will not copy data
   259      * unnecessarily.
   260      *
   261      * @param      cbuf  Destination buffer
   262      * @param      off   Offset at which to start storing characters
   263      * @param      len   Maximum number of characters to read
   264      *
   265      * @return     The number of characters read, or -1 if the end of the
   266      *             stream has been reached
   267      *
   268      * @exception  IOException  If an I/O error occurs
   269      */
   270     public int read(char cbuf[], int off, int len) throws IOException {
   271         synchronized (lock) {
   272             ensureOpen();
   273             if ((off < 0) || (off > cbuf.length) || (len < 0) ||
   274                 ((off + len) > cbuf.length) || ((off + len) < 0)) {
   275                 throw new IndexOutOfBoundsException();
   276             } else if (len == 0) {
   277                 return 0;
   278             }
   279 
   280             int n = read1(cbuf, off, len);
   281             if (n <= 0) return n;
   282             while ((n < len) && in.ready()) {
   283                 int n1 = read1(cbuf, off + n, len - n);
   284                 if (n1 <= 0) break;
   285                 n += n1;
   286             }
   287             return n;
   288         }
   289     }
   290 
   291     /**
   292      * Reads a line of text.  A line is considered to be terminated by any one
   293      * of a line feed ('\n'), a carriage return ('\r'), or a carriage return
   294      * followed immediately by a linefeed.
   295      *
   296      * @param      ignoreLF  If true, the next '\n' will be skipped
   297      *
   298      * @return     A String containing the contents of the line, not including
   299      *             any line-termination characters, or null if the end of the
   300      *             stream has been reached
   301      *
   302      * @see        java.io.LineNumberReader#readLine()
   303      *
   304      * @exception  IOException  If an I/O error occurs
   305      */
   306     String readLine(boolean ignoreLF) throws IOException {
   307         StringBuffer s = null;
   308         int startChar;
   309 
   310         synchronized (lock) {
   311             ensureOpen();
   312             boolean omitLF = ignoreLF || skipLF;
   313 
   314         bufferLoop:
   315             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:
   336                 for (i = nextChar; i < nChars; i++) {
   337                     c = cb[i];
   338                     if ((c == '\n') || (c == '\r')) {
   339                         eol = true;
   340                         break charLoop;
   341                     }
   342                 }
   343 
   344                 startChar = nextChar;
   345                 nextChar = i;
   346 
   347                 if (eol) {
   348                     String str;
   349                     if (s == null) {
   350                         str = new String(cb, startChar, i - startChar);
   351                     } else {
   352                         s.append(cb, startChar, i - startChar);
   353                         str = s.toString();
   354                     }
   355                     nextChar++;
   356                     if (c == '\r') {
   357                         skipLF = true;
   358                     }
   359                     return str;
   360                 }
   361 
   362                 if (s == null)
   363                     s = new StringBuffer(defaultExpectedLineLength);
   364                 s.append(cb, startChar, i - startChar);
   365             }
   366         }
   367     }
   368 
   369     /**
   370      * Reads a line of text.  A line is considered to be terminated by any one
   371      * of a line feed ('\n'), a carriage return ('\r'), or a carriage return
   372      * followed immediately by a linefeed.
   373      *
   374      * @return     A String containing the contents of the line, not including
   375      *             any line-termination characters, or null if the end of the
   376      *             stream has been reached
   377      *
   378      * @exception  IOException  If an I/O error occurs
   379      *
   380      * @see java.nio.file.Files#readAllLines
   381      */
   382     public String readLine() throws IOException {
   383         return readLine(false);
   384     }
   385 
   386     /**
   387      * Skips characters.
   388      *
   389      * @param  n  The number of characters to skip
   390      *
   391      * @return    The number of characters actually skipped
   392      *
   393      * @exception  IllegalArgumentException  If <code>n</code> is negative.
   394      * @exception  IOException  If an I/O error occurs
   395      */
   396     public long skip(long n) throws IOException {
   397         if (n < 0L) {
   398             throw new IllegalArgumentException("skip value is negative");
   399         }
   400         synchronized (lock) {
   401             ensureOpen();
   402             long r = n;
   403             while (r > 0) {
   404                 if (nextChar >= nChars)
   405                     fill();
   406                 if (nextChar >= nChars) /* EOF */
   407                     break;
   408                 if (skipLF) {
   409                     skipLF = false;
   410                     if (cb[nextChar] == '\n') {
   411                         nextChar++;
   412                     }
   413                 }
   414                 long d = nChars - nextChar;
   415                 if (r <= d) {
   416                     nextChar += r;
   417                     r = 0;
   418                     break;
   419                 }
   420                 else {
   421                     r -= d;
   422                     nextChar = nChars;
   423                 }
   424             }
   425             return n - r;
   426         }
   427     }
   428 
   429     /**
   430      * Tells whether this stream is ready to be read.  A buffered character
   431      * stream is ready if the buffer is not empty, or if the underlying
   432      * character stream is ready.
   433      *
   434      * @exception  IOException  If an I/O error occurs
   435      */
   436     public boolean ready() throws IOException {
   437         synchronized (lock) {
   438             ensureOpen();
   439 
   440             /*
   441              * If newline needs to be skipped and the next char to be read
   442              * is a newline character, then just skip it right away.
   443              */
   444             if (skipLF) {
   445                 /* Note that in.ready() will return true if and only if the next
   446                  * read on the stream will not block.
   447                  */
   448                 if (nextChar >= nChars && in.ready()) {
   449                     fill();
   450                 }
   451                 if (nextChar < nChars) {
   452                     if (cb[nextChar] == '\n')
   453                         nextChar++;
   454                     skipLF = false;
   455                 }
   456             }
   457             return (nextChar < nChars) || in.ready();
   458         }
   459     }
   460 
   461     /**
   462      * Tells whether this stream supports the mark() operation, which it does.
   463      */
   464     public boolean markSupported() {
   465         return true;
   466     }
   467 
   468     /**
   469      * Marks the present position in the stream.  Subsequent calls to reset()
   470      * will attempt to reposition the stream to this point.
   471      *
   472      * @param readAheadLimit   Limit on the number of characters that may be
   473      *                         read while still preserving the mark. An attempt
   474      *                         to reset the stream after reading characters
   475      *                         up to this limit or beyond may fail.
   476      *                         A limit value larger than the size of the input
   477      *                         buffer will cause a new buffer to be allocated
   478      *                         whose size is no smaller than limit.
   479      *                         Therefore large values should be used with care.
   480      *
   481      * @exception  IllegalArgumentException  If readAheadLimit is < 0
   482      * @exception  IOException  If an I/O error occurs
   483      */
   484     public void mark(int readAheadLimit) throws IOException {
   485         if (readAheadLimit < 0) {
   486             throw new IllegalArgumentException("Read-ahead limit < 0");
   487         }
   488         synchronized (lock) {
   489             ensureOpen();
   490             this.readAheadLimit = readAheadLimit;
   491             markedChar = nextChar;
   492             markedSkipLF = skipLF;
   493         }
   494     }
   495 
   496     /**
   497      * Resets the stream to the most recent mark.
   498      *
   499      * @exception  IOException  If the stream has never been marked,
   500      *                          or if the mark has been invalidated
   501      */
   502     public void reset() throws IOException {
   503         synchronized (lock) {
   504             ensureOpen();
   505             if (markedChar < 0)
   506                 throw new IOException((markedChar == INVALIDATED)
   507                                       ? "Mark invalid"
   508                                       : "Stream not marked");
   509             nextChar = markedChar;
   510             skipLF = markedSkipLF;
   511         }
   512     }
   513 
   514     public void close() throws IOException {
   515         synchronized (lock) {
   516             if (in == null)
   517                 return;
   518             in.close();
   519             in = null;
   520             cb = null;
   521         }
   522     }
   523 }