Save This Page
Home » openjdk-7 » java » io » [javadoc | source]
    1   /*
    2    * Copyright 1996-2006 Sun Microsystems, Inc.  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.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any 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   }

Save This Page
Home » openjdk-7 » java » io » [javadoc | source]