Home | History | Annotate | Download | only in io
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
      4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      5  *
      6  * This code is free software; you can redistribute it and/or modify it
      7  * under the terms of the GNU General Public License version 2 only, as
      8  * published by the Free Software Foundation.  Oracle designates this
      9  * particular file as subject to the "Classpath" exception as provided
     10  * by Oracle in the LICENSE file that accompanied this code.
     11  *
     12  * This code is distributed in the hope that it will be useful, but WITHOUT
     13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     15  * version 2 for more details (a copy is included in the LICENSE file that
     16  * accompanied this code).
     17  *
     18  * You should have received a copy of the GNU General Public License version
     19  * 2 along with this work; if not, write to the Free Software Foundation,
     20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     21  *
     22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     23  * or visit www.oracle.com if you need additional information or have any
     24  * questions.
     25  */
     26 
     27 package java.io;
     28 
     29 
     30 import java.util.Iterator;
     31 import java.util.NoSuchElementException;
     32 import java.util.Spliterator;
     33 import java.util.Spliterators;
     34 import java.util.stream.Stream;
     35 import java.util.stream.StreamSupport;
     36 
     37 /**
     38  * Reads text from a character-input stream, buffering characters so as to
     39  * provide for the efficient reading of characters, arrays, and lines.
     40  *
     41  * <p> The buffer size may be specified, or the default size may be used.  The
     42  * default is large enough for most purposes.
     43  *
     44  * <p> In general, each read request made of a Reader causes a corresponding
     45  * read request to be made of the underlying character or byte stream.  It is
     46  * therefore advisable to wrap a BufferedReader around any Reader whose read()
     47  * operations may be costly, such as FileReaders and InputStreamReaders.  For
     48  * example,
     49  *
     50  * <pre>
     51  * BufferedReader in
     52  *   = new BufferedReader(new FileReader("foo.in"));
     53  * </pre>
     54  *
     55  * will buffer the input from the specified file.  Without buffering, each
     56  * invocation of read() or readLine() could cause bytes to be read from the
     57  * file, converted into characters, and then returned, which can be very
     58  * inefficient.
     59  *
     60  * <p> Programs that use DataInputStreams for textual input can be localized by
     61  * replacing each DataInputStream with an appropriate BufferedReader.
     62  *
     63  * @see FileReader
     64  * @see InputStreamReader
     65  * @see java.nio.file.Files#newBufferedReader
     66  *
     67  * @author      Mark Reinhold
     68  * @since       JDK1.1
     69  */
     70 
     71 public class BufferedReader extends Reader {
     72 
     73     private Reader in;
     74 
     75     private char cb[];
     76     private int nChars, nextChar;
     77 
     78     private static final int INVALIDATED = -2;
     79     private static final int UNMARKED = -1;
     80     private int markedChar = UNMARKED;
     81     private int readAheadLimit = 0; /* Valid only when markedChar > 0 */
     82 
     83     /** If the next character is a line feed, skip it */
     84     private boolean skipLF = false;
     85 
     86     /** The skipLF flag when the mark was set */
     87     private boolean markedSkipLF = false;
     88 
     89     private static int defaultCharBufferSize = 8192;
     90     private static int defaultExpectedLineLength = 80;
     91 
     92     /**
     93      * Creates a buffering character-input stream that uses an input buffer of
     94      * the specified size.
     95      *
     96      * @param  in   A Reader
     97      * @param  sz   Input-buffer size
     98      *
     99      * @exception  IllegalArgumentException  If {@code sz <= 0}
    100      */
    101     public BufferedReader(Reader in, int sz) {
    102         super(in);
    103         if (sz <= 0)
    104             throw new IllegalArgumentException("Buffer size <= 0");
    105         this.in = in;
    106         cb = new char[sz];
    107         nextChar = nChars = 0;
    108     }
    109 
    110     /**
    111      * Creates a buffering character-input stream that uses a default-sized
    112      * input buffer.
    113      *
    114      * @param  in   A Reader
    115      */
    116     public BufferedReader(Reader in) {
    117         this(in, defaultCharBufferSize);
    118     }
    119 
    120     /** Checks to make sure that the stream has not been closed */
    121     private void ensureOpen() throws IOException {
    122         if (in == null)
    123             throw new IOException("Stream closed");
    124     }
    125 
    126     /**
    127      * Fills the input buffer, taking the mark into account if it is valid.
    128      */
    129     private void fill() throws IOException {
    130         int dst;
    131         if (markedChar <= UNMARKED) {
    132             /* No mark */
    133             dst = 0;
    134         } else {
    135             /* Marked */
    136             int delta = nextChar - markedChar;
    137             if (delta >= readAheadLimit) {
    138                 /* Gone past read-ahead limit: Invalidate mark */
    139                 markedChar = INVALIDATED;
    140                 readAheadLimit = 0;
    141                 dst = 0;
    142             } else {
    143                 if (readAheadLimit <= cb.length) {
    144                     /* Shuffle in the current buffer */
    145                     System.arraycopy(cb, markedChar, cb, 0, delta);
    146                     markedChar = 0;
    147                     dst = delta;
    148                 } else {
    149                     /* Reallocate buffer to accommodate read-ahead limit */
    150                     //
    151                     // Android-changed: Use the same strategy as BufferedInputStream,
    152                     // i.e, double the size of the buffer on each fill. Do not directly
    153                     // size the buffer to the readAheadLimit.
    154                     //
    155                     // char ncb[] = new char[readAheadLimit];
    156                     int nlength = cb.length * 2;
    157                     if (nlength > readAheadLimit) {
    158                         nlength = readAheadLimit;
    159                     }
    160                     char ncb[] = new char[nlength];
    161                     System.arraycopy(cb, markedChar, ncb, 0, delta);
    162                     cb = ncb;
    163                     markedChar = 0;
    164                     dst = delta;
    165                 }
    166                 nextChar = nChars = delta;
    167             }
    168         }
    169 
    170         int n;
    171         do {
    172             n = in.read(cb, dst, cb.length - dst);
    173         } while (n == 0);
    174         if (n > 0) {
    175             nChars = dst + n;
    176             nextChar = dst;
    177         }
    178     }
    179 
    180     /**
    181      * Reads a single character.
    182      *
    183      * @return The character read, as an integer in the range
    184      *         0 to 65535 (<tt>0x00-0xffff</tt>), or -1 if the
    185      *         end of the stream has been reached
    186      * @exception  IOException  If an I/O error occurs
    187      */
    188     public int read() throws IOException {
    189         synchronized (lock) {
    190             ensureOpen();
    191             for (;;) {
    192                 if (nextChar >= nChars) {
    193                     fill();
    194                     if (nextChar >= nChars)
    195                         return -1;
    196                 }
    197                 if (skipLF) {
    198                     skipLF = false;
    199                     if (cb[nextChar] == '\n') {
    200                         nextChar++;
    201                         continue;
    202                     }
    203                 }
    204                 return cb[nextChar++];
    205             }
    206         }
    207     }
    208 
    209     /**
    210      * Reads characters into a portion of an array, reading from the underlying
    211      * stream if necessary.
    212      */
    213     private int read1(char[] cbuf, int off, int len) throws IOException {
    214         if (nextChar >= nChars) {
    215             /* If the requested length is at least as large as the buffer, and
    216                if there is no mark/reset activity, and if line feeds are not
    217                being skipped, do not bother to copy the characters into the
    218                local buffer.  In this way buffered streams will cascade
    219                harmlessly. */
    220             if (len >= cb.length && markedChar <= UNMARKED && !skipLF) {
    221                 return in.read(cbuf, off, len);
    222             }
    223             fill();
    224         }
    225         if (nextChar >= nChars) return -1;
    226         if (skipLF) {
    227             skipLF = false;
    228             if (cb[nextChar] == '\n') {
    229                 nextChar++;
    230                 if (nextChar >= nChars)
    231                     fill();
    232                 if (nextChar >= nChars)
    233                     return -1;
    234             }
    235         }
    236         int n = Math.min(len, nChars - nextChar);
    237         System.arraycopy(cb, nextChar, cbuf, off, n);
    238         nextChar += n;
    239         return n;
    240     }
    241 
    242     /**
    243      * Reads characters into a portion of an array.
    244      *
    245      * <p> This method implements the general contract of the corresponding
    246      * <code>{@link Reader#read(char[], int, int) read}</code> method of the
    247      * <code>{@link Reader}</code> class.  As an additional convenience, it
    248      * attempts to read as many characters as possible by repeatedly invoking
    249      * the <code>read</code> method of the underlying stream.  This iterated
    250      * <code>read</code> continues until one of the following conditions becomes
    251      * true: <ul>
    252      *
    253      *   <li> The specified number of characters have been read,
    254      *
    255      *   <li> The <code>read</code> method of the underlying stream returns
    256      *   <code>-1</code>, indicating end-of-file, or
    257      *
    258      *   <li> The <code>ready</code> method of the underlying stream
    259      *   returns <code>false</code>, indicating that further input requests
    260      *   would block.
    261      *
    262      * </ul> If the first <code>read</code> on the underlying stream returns
    263      * <code>-1</code> to indicate end-of-file then this method returns
    264      * <code>-1</code>.  Otherwise this method returns the number of characters
    265      * actually read.
    266      *
    267      * <p> Subclasses of this class are encouraged, but not required, to
    268      * attempt to read as many characters as possible in the same fashion.
    269      *
    270      * <p> Ordinarily this method takes characters from this stream's character
    271      * buffer, filling it from the underlying stream as necessary.  If,
    272      * however, the buffer is empty, the mark is not valid, and the requested
    273      * length is at least as large as the buffer, then this method will read
    274      * characters directly from the underlying stream into the given array.
    275      * Thus redundant <code>BufferedReader</code>s will not copy data
    276      * unnecessarily.
    277      *
    278      * @param      cbuf  Destination buffer
    279      * @param      off   Offset at which to start storing characters
    280      * @param      len   Maximum number of characters to read
    281      *
    282      * @return     The number of characters read, or -1 if the end of the
    283      *             stream has been reached
    284      *
    285      * @exception  IOException  If an I/O error occurs
    286      */
    287     public int read(char cbuf[], int off, int len) throws IOException {
    288         synchronized (lock) {
    289             ensureOpen();
    290             if ((off < 0) || (off > cbuf.length) || (len < 0) ||
    291                 ((off + len) > cbuf.length) || ((off + len) < 0)) {
    292                 throw new IndexOutOfBoundsException();
    293             } else if (len == 0) {
    294                 return 0;
    295             }
    296 
    297             int n = read1(cbuf, off, len);
    298             if (n <= 0) return n;
    299             while ((n < len) && in.ready()) {
    300                 int n1 = read1(cbuf, off + n, len - n);
    301                 if (n1 <= 0) break;
    302                 n += n1;
    303             }
    304             return n;
    305         }
    306     }
    307 
    308     /**
    309      * Reads a line of text.  A line is considered to be terminated by any one
    310      * of a line feed ('\n'), a carriage return ('\r'), or a carriage return
    311      * followed immediately by a linefeed.
    312      *
    313      * @param      ignoreLF  If true, the next '\n' will be skipped
    314      *
    315      * @return     A String containing the contents of the line, not including
    316      *             any line-termination characters, or null if the end of the
    317      *             stream has been reached
    318      *
    319      * @see        java.io.LineNumberReader#readLine()
    320      *
    321      * @exception  IOException  If an I/O error occurs
    322      */
    323     String readLine(boolean ignoreLF) throws IOException {
    324         StringBuffer s = null;
    325         int startChar;
    326 
    327         synchronized (lock) {
    328             ensureOpen();
    329             boolean omitLF = ignoreLF || skipLF;
    330 
    331         bufferLoop:
    332             for (;;) {
    333 
    334                 if (nextChar >= nChars)
    335                     fill();
    336                 if (nextChar >= nChars) { /* EOF */
    337                     if (s != null && s.length() > 0)
    338                         return s.toString();
    339                     else
    340                         return null;
    341                 }
    342                 boolean eol = false;
    343                 char c = 0;
    344                 int i;
    345 
    346                 /* Skip a leftover '\n', if necessary */
    347                 if (omitLF && (cb[nextChar] == '\n'))
    348                     nextChar++;
    349                 skipLF = false;
    350                 omitLF = false;
    351 
    352             charLoop:
    353                 for (i = nextChar; i < nChars; i++) {
    354                     c = cb[i];
    355                     if ((c == '\n') || (c == '\r')) {
    356                         eol = true;
    357                         break charLoop;
    358                     }
    359                 }
    360 
    361                 startChar = nextChar;
    362                 nextChar = i;
    363 
    364                 if (eol) {
    365                     String str;
    366                     if (s == null) {
    367                         str = new String(cb, startChar, i - startChar);
    368                     } else {
    369                         s.append(cb, startChar, i - startChar);
    370                         str = s.toString();
    371                     }
    372                     nextChar++;
    373                     if (c == '\r') {
    374                         skipLF = true;
    375                     }
    376                     return str;
    377                 }
    378 
    379                 if (s == null)
    380                     s = new StringBuffer(defaultExpectedLineLength);
    381                 s.append(cb, startChar, i - startChar);
    382             }
    383         }
    384     }
    385 
    386     /**
    387      * Reads a line of text.  A line is considered to be terminated by any one
    388      * of a line feed ('\n'), a carriage return ('\r'), or a carriage return
    389      * followed immediately by a linefeed.
    390      *
    391      * @return     A String containing the contents of the line, not including
    392      *             any line-termination characters, or null if the end of the
    393      *             stream has been reached
    394      *
    395      * @exception  IOException  If an I/O error occurs
    396      *
    397      * @see java.nio.file.Files#readAllLines
    398      */
    399     public String readLine() throws IOException {
    400         return readLine(false);
    401     }
    402 
    403     /**
    404      * Skips characters.
    405      *
    406      * @param  n  The number of characters to skip
    407      *
    408      * @return    The number of characters actually skipped
    409      *
    410      * @exception  IllegalArgumentException  If <code>n</code> is negative.
    411      * @exception  IOException  If an I/O error occurs
    412      */
    413     public long skip(long n) throws IOException {
    414         if (n < 0L) {
    415             throw new IllegalArgumentException("skip value is negative");
    416         }
    417         synchronized (lock) {
    418             ensureOpen();
    419             long r = n;
    420             while (r > 0) {
    421                 if (nextChar >= nChars)
    422                     fill();
    423                 if (nextChar >= nChars) /* EOF */
    424                     break;
    425                 if (skipLF) {
    426                     skipLF = false;
    427                     if (cb[nextChar] == '\n') {
    428                         nextChar++;
    429                     }
    430                 }
    431                 long d = nChars - nextChar;
    432                 if (r <= d) {
    433                     nextChar += r;
    434                     r = 0;
    435                     break;
    436                 }
    437                 else {
    438                     r -= d;
    439                     nextChar = nChars;
    440                 }
    441             }
    442             return n - r;
    443         }
    444     }
    445 
    446     /**
    447      * Tells whether this stream is ready to be read.  A buffered character
    448      * stream is ready if the buffer is not empty, or if the underlying
    449      * character stream is ready.
    450      *
    451      * @exception  IOException  If an I/O error occurs
    452      */
    453     public boolean ready() throws IOException {
    454         synchronized (lock) {
    455             ensureOpen();
    456 
    457             /*
    458              * If newline needs to be skipped and the next char to be read
    459              * is a newline character, then just skip it right away.
    460              */
    461             if (skipLF) {
    462                 /* Note that in.ready() will return true if and only if the next
    463                  * read on the stream will not block.
    464                  */
    465                 if (nextChar >= nChars && in.ready()) {
    466                     fill();
    467                 }
    468                 if (nextChar < nChars) {
    469                     if (cb[nextChar] == '\n')
    470                         nextChar++;
    471                     skipLF = false;
    472                 }
    473             }
    474             return (nextChar < nChars) || in.ready();
    475         }
    476     }
    477 
    478     /**
    479      * Tells whether this stream supports the mark() operation, which it does.
    480      */
    481     public boolean markSupported() {
    482         return true;
    483     }
    484 
    485     /**
    486      * Marks the present position in the stream.  Subsequent calls to reset()
    487      * will attempt to reposition the stream to this point.
    488      *
    489      * @param readAheadLimit   Limit on the number of characters that may be
    490      *                         read while still preserving the mark. An attempt
    491      *                         to reset the stream after reading characters
    492      *                         up to this limit or beyond may fail.
    493      *                         A limit value larger than the size of the input
    494      *                         buffer will cause a new buffer to be allocated
    495      *                         whose size is no smaller than limit.
    496      *                         Therefore large values should be used with care.
    497      *
    498      * @exception  IllegalArgumentException  If {@code readAheadLimit < 0}
    499      * @exception  IOException  If an I/O error occurs
    500      */
    501     public void mark(int readAheadLimit) throws IOException {
    502         if (readAheadLimit < 0) {
    503             throw new IllegalArgumentException("Read-ahead limit < 0");
    504         }
    505         synchronized (lock) {
    506             ensureOpen();
    507             this.readAheadLimit = readAheadLimit;
    508             markedChar = nextChar;
    509             markedSkipLF = skipLF;
    510         }
    511     }
    512 
    513     /**
    514      * Resets the stream to the most recent mark.
    515      *
    516      * @exception  IOException  If the stream has never been marked,
    517      *                          or if the mark has been invalidated
    518      */
    519     public void reset() throws IOException {
    520         synchronized (lock) {
    521             ensureOpen();
    522             if (markedChar < 0)
    523                 throw new IOException((markedChar == INVALIDATED)
    524                                       ? "Mark invalid"
    525                                       : "Stream not marked");
    526             nextChar = markedChar;
    527             skipLF = markedSkipLF;
    528         }
    529     }
    530 
    531     public void close() throws IOException {
    532         synchronized (lock) {
    533             if (in == null)
    534                 return;
    535             try {
    536                 in.close();
    537             } finally {
    538                 in = null;
    539                 cb = null;
    540             }
    541         }
    542     }
    543 
    544     /**
    545      * Returns a {@code Stream}, the elements of which are lines read from
    546      * this {@code BufferedReader}.  The {@link Stream} is lazily populated,
    547      * i.e., read only occurs during the
    548      * <a href="../util/stream/package-summary.html#StreamOps">terminal
    549      * stream operation</a>.
    550      *
    551      * <p> The reader must not be operated on during the execution of the
    552      * terminal stream operation. Otherwise, the result of the terminal stream
    553      * operation is undefined.
    554      *
    555      * <p> After execution of the terminal stream operation there are no
    556      * guarantees that the reader will be at a specific position from which to
    557      * read the next character or line.
    558      *
    559      * <p> If an {@link IOException} is thrown when accessing the underlying
    560      * {@code BufferedReader}, it is wrapped in an {@link
    561      * UncheckedIOException} which will be thrown from the {@code Stream}
    562      * method that caused the read to take place. This method will return a
    563      * Stream if invoked on a BufferedReader that is closed. Any operation on
    564      * that stream that requires reading from the BufferedReader after it is
    565      * closed, will cause an UncheckedIOException to be thrown.
    566      *
    567      * @return a {@code Stream<String>} providing the lines of text
    568      *         described by this {@code BufferedReader}
    569      *
    570      * @since 1.8
    571      */
    572     public Stream<String> lines() {
    573         Iterator<String> iter = new Iterator<String>() {
    574             String nextLine = null;
    575 
    576             @Override
    577             public boolean hasNext() {
    578                 if (nextLine != null) {
    579                     return true;
    580                 } else {
    581                     try {
    582                         nextLine = readLine();
    583                         return (nextLine != null);
    584                     } catch (IOException e) {
    585                         throw new UncheckedIOException(e);
    586                     }
    587                 }
    588             }
    589 
    590             @Override
    591             public String next() {
    592                 if (nextLine != null || hasNext()) {
    593                     String line = nextLine;
    594                     nextLine = null;
    595                     return line;
    596                 } else {
    597                     throw new NoSuchElementException();
    598                 }
    599             }
    600         };
    601         return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
    602                 iter, Spliterator.ORDERED | Spliterator.NONNULL), false);
    603     }
    604 }
    605