home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / 3rdParty / jbuilder / unsupported / JDK1.2beta3 / SOURCE / SRC.ZIP / java / io / BufferedReader.java < prev    next >
Encoding:
Java Source  |  1998-03-20  |  10.9 KB  |  399 lines

  1. /*
  2.  * @(#)BufferedReader.java    1.14 98/03/18
  3.  *
  4.  * Copyright 1996-1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package java.io;
  16.  
  17.  
  18. /**
  19.  * Read text from a character-input stream, buffering characters so as to
  20.  * provide for the efficient reading of characters, arrays, and lines.
  21.  *
  22.  * <p> The buffer size may be specified, or the default size may be used.  The
  23.  * default is large enough for most purposes.
  24.  *
  25.  * <p> In general, each read request made of a Reader causes a corresponding
  26.  * read request to be made of the underlying character or byte stream.  It is
  27.  * therefore advisable to wrap a BufferedReader around any Reader whose read()
  28.  * operations may be costly, such as FileReaders and InputStreamReaders.  For
  29.  * example,
  30.  *
  31.  * <pre>
  32.  * BufferedReader in
  33.  *   = new BufferedReader(new FileReader("foo.in"));
  34.  * </pre>
  35.  *
  36.  * will buffer the input from the specified file.  Without buffering, each
  37.  * invocation of read() or readLine() could cause bytes to be read from the
  38.  * file, converted into characters, and then returned, which can be very
  39.  * inefficient. 
  40.  *
  41.  * <p> Programs that use DataInputStreams for textual input can be localized by
  42.  * replacing each DataInputStream with an appropriate BufferedReader.
  43.  *
  44.  * @see FileReader
  45.  * @see InputStreamReader
  46.  *
  47.  * @version     1.14, 98/03/18
  48.  * @author    Mark Reinhold
  49.  * @since    JDK1.1
  50.  */
  51.  
  52. public class BufferedReader extends Reader {
  53.  
  54.     private Reader in;
  55.  
  56.     private char cb[];
  57.     private int nChars, nextChar;
  58.  
  59.     private static final int INVALIDATED = -2;
  60.     private static final int UNMARKED = -1;
  61.     private int markedChar = UNMARKED;
  62.     private int readAheadLimit = 0; /* Valid only when markedChar > 0 */
  63.  
  64.     private static int defaultCharBufferSize = 8192;
  65.     private static int defaultExpectedLineLength = 80;
  66.  
  67.     /**
  68.      * Create a buffering character-input stream that uses an input buffer of
  69.      * the specified size.
  70.      *
  71.      * @param  in   A Reader
  72.      * @param  sz   Input-buffer size
  73.      *
  74.      * @exception  IllegalArgumentException  If sz is <= 0
  75.      */
  76.     public BufferedReader(Reader in, int sz) {
  77.     super(in);
  78.     if (sz <= 0)
  79.         throw new IllegalArgumentException("Buffer size <= 0");
  80.     this.in = in;
  81.     cb = new char[sz];
  82.     nextChar = nChars = 0;
  83.     }
  84.  
  85.     /**
  86.      * Create a buffering character-input stream that uses a default-sized
  87.      * input buffer.
  88.      *
  89.      * @param  in   A Reader
  90.      */
  91.     public BufferedReader(Reader in) {
  92.     this(in, defaultCharBufferSize);
  93.     }
  94.  
  95.     /** Check to make sure that the stream has not been closed */
  96.     private void ensureOpen() throws IOException {
  97.     if (in == null)
  98.         throw new IOException("Stream closed");
  99.     }
  100.  
  101.     /**
  102.      * Fill the input buffer, taking the mark into account if it is valid.
  103.      */
  104.     private void fill() throws IOException {
  105.     int dst;
  106.     if (markedChar <= UNMARKED) {
  107.         /* No mark */
  108.         dst = 0;
  109.     } else {
  110.         /* Marked */
  111.         int delta = nextChar - markedChar;
  112.         if (delta >= readAheadLimit) {
  113.         /* Gone past read-ahead limit: Invalidate mark */
  114.         markedChar = INVALIDATED;
  115.         readAheadLimit = 0;
  116.         dst = 0;
  117.         } else {
  118.         if (readAheadLimit <= cb.length) {
  119.             /* Shuffle in the current buffer */
  120.             System.arraycopy(cb, markedChar, cb, 0, delta);
  121.             markedChar = 0;
  122.             dst = delta;
  123.         } else {
  124.             /* Reallocate buffer to accomodate read-ahead limit */
  125.             char ncb[] = new char[readAheadLimit];
  126.             System.arraycopy(cb, markedChar, ncb, 0, delta);
  127.             cb = ncb;
  128.             markedChar = 0;
  129.             dst = delta;
  130.         }
  131.         }
  132.     }
  133.  
  134.     int n;
  135.     do {
  136.         n = in.read(cb, dst, cb.length - dst);
  137.     } while (n == 0);
  138.     if (n > 0) {
  139.         nChars = dst + n;
  140.         nextChar = dst;
  141.     }
  142.     }
  143.  
  144.     /**
  145.      * Read a single character.
  146.      *
  147.      * @exception  IOException  If an I/O error occurs
  148.      */
  149.     public int read() throws IOException {
  150.     synchronized (lock) {
  151.         ensureOpen();
  152.         if (nextChar >= nChars) {
  153.         fill();
  154.         if (nextChar >= nChars)
  155.             return -1;
  156.         }
  157.         return cb[nextChar++];
  158.     }
  159.     }
  160.  
  161.     /**
  162.      * Read characters into a portion of an array.
  163.      *
  164.      * <p> Ordinarily this method takes characters from this stream's character
  165.      * buffer, filling it from the underlying stream as necessary.  If,
  166.      * however, the buffer is empty, the mark is not valid, and the requested
  167.      * length is at least as large as the buffer, then this method will read
  168.      * characters directly from the underlying stream into the given array.
  169.      * Thus redundant <code>BufferedReader</code>s will not copy data
  170.      * unnecessarily.
  171.      *
  172.      * @param      cbuf  Destination buffer
  173.      * @param      off   Offset at which to start storing characters
  174.      * @param      len   Maximum number of characters to read
  175.      *
  176.      * @return     The number of bytes read, or -1 if the end of the stream has
  177.      *             been reached
  178.      *
  179.      * @exception  IOException  If an I/O error occurs
  180.      */
  181.     public int read(char cbuf[], int off, int len) throws IOException {
  182.     synchronized (lock) {
  183.         ensureOpen();
  184.         if (nextChar >= nChars) {
  185.         /* If the requested length is larger than the buffer, and if
  186.            there is no mark/reset activity, do not bother to copy the
  187.            bytes into the local buffer.  In this way buffered streams
  188.            will cascade harmlessly. */
  189.         if (len >= cb.length && markedChar <= UNMARKED) {
  190.             return in.read(cbuf, off, len);
  191.         }
  192.         fill();
  193.         }
  194.         if (nextChar >= nChars)
  195.         return -1;
  196.         int n = Math.min(len, nChars - nextChar);
  197.         System.arraycopy(cb, nextChar,
  198.                  cbuf, off, n);
  199.         nextChar += n;
  200.         return n;
  201.     }
  202.     }
  203.  
  204.     /**
  205.      * Read a line of text.  A line is considered to be terminated by any one
  206.      * of a line feed ('\n'), a carriage return ('\r'), or a carriage return
  207.      * followed immediately by a linefeed.
  208.      *
  209.      * @param      skipLF  If true, the next '\n' will be skipped
  210.      *
  211.      * @return     A String containing the contents of the line, not including
  212.      *             any line-termination characters, or null if the end of the
  213.      *             stream has been reached
  214.      * 
  215.      * @see        java.io.LineNumberReader#readLine()
  216.      *
  217.      * @exception  IOException  If an I/O error occurs
  218.      */
  219.     String readLine(boolean skipLF) throws IOException {
  220.     StringBuffer s = new StringBuffer(defaultExpectedLineLength);
  221.     synchronized (lock) {
  222.         ensureOpen();
  223.  
  224.     bufferLoop:
  225.         for (;;) {
  226.  
  227.         if (nextChar >= nChars)
  228.             fill();
  229.         if (nextChar >= nChars) { /* EOF */
  230.             if (s.length() > 0)
  231.             return s.toString();
  232.             else
  233.             return null;
  234.         }
  235.         boolean eol = false;
  236.         char c = 0;
  237.         int i;
  238.  
  239.                 /* Skip a leftover '\n' */
  240.         if (skipLF && (cb[nextChar] == '\n'))
  241.                     nextChar++;
  242.  
  243.         charLoop:
  244.         for (i = nextChar; i < nChars; i++) {
  245.             c = cb[i];
  246.             if ((c == '\n') || (c == '\r')) {
  247.             eol = true;
  248.             break charLoop;
  249.             }
  250.         }
  251.         s.append(cb, nextChar, i - nextChar);
  252.         nextChar = i;
  253.  
  254.         if (eol) {
  255.             nextChar++;
  256.             if (c == '\r') {
  257.             if (nextChar >= nChars)
  258.                 fill();
  259.             if ((nextChar < nChars) && (cb[nextChar] == '\n'))
  260.                 nextChar++;
  261.             }
  262.             break bufferLoop;
  263.         }
  264.         }
  265.     }
  266.  
  267.     return s.toString();
  268.     }
  269.  
  270.     /**
  271.      * Read a line of text.  A line is considered to be terminated by any one
  272.      * of a line feed ('\n'), a carriage return ('\r'), or a carriage return
  273.      * followed immediately by a linefeed.
  274.      *
  275.      * @return     A String containing the contents of the line, not including
  276.      *             any line-termination characters, or null if the end of the
  277.      *             stream has been reached
  278.      *
  279.      * @exception  IOException  If an I/O error occurs
  280.      */
  281.     public String readLine() throws IOException {
  282.         return readLine(false);
  283.     }
  284.  
  285.     /**
  286.      * Skip characters.
  287.      *
  288.      * @param  n  The number of characters to skip
  289.      *
  290.      * @return    The number of characters actually skipped
  291.      *
  292.      * @exception  IOException  If an I/O error occurs
  293.      */
  294.     public long skip(long n) throws IOException {
  295.     synchronized (lock) {
  296.         ensureOpen();
  297.         long r = n;
  298.         while (r > 0) {
  299.         if (nextChar >= nChars)
  300.             fill();
  301.         if (nextChar >= nChars)    /* EOF */
  302.             break;
  303.         long d = nChars - nextChar;
  304.         if (r <= d) {
  305.             nextChar += r;
  306.             r = 0;
  307.             break;
  308.         }
  309.         else {
  310.             r -= d;
  311.             nextChar = nChars;
  312.         }
  313.         }
  314.         return n - r;
  315.     }
  316.     }
  317.  
  318.     /**
  319.      * Tell whether this stream is ready to be read.  A buffered character
  320.      * stream is ready if the buffer is not empty, or if the underlying
  321.      * character stream is ready.
  322.      *
  323.      * @exception  IOException  If an I/O error occurs
  324.      */
  325.     public boolean ready() throws IOException {
  326.     synchronized (lock) {
  327.         ensureOpen();
  328.         return (nextChar < nChars) || in.ready();
  329.     }
  330.     }
  331.  
  332.     /**
  333.      * Tell whether this stream supports the mark() operation, which it does.
  334.      */
  335.     public boolean markSupported() {
  336.     return true;
  337.     }
  338.  
  339.     /**
  340.      * Mark the present position in the stream.  Subsequent calls to reset()
  341.      * will attempt to reposition the stream to this point.
  342.      *
  343.      * @param readAheadLimit   Limit on the number of characters that may be
  344.      *                         read while still preserving the mark.  After
  345.      *                         reading this many characters, attempting to
  346.      *                         reset the stream may fail.  A limit value larger
  347.      *                         than the size of the input buffer will cause a
  348.      *                         new buffer to be allocated whose size is no
  349.      *                         smaller than limit.  Therefore large values
  350.      *                         should be used with care.
  351.      *
  352.      * @exception  IllegalArgumentException  If readAheadLimit is < 0
  353.      * @exception  IOException  If an I/O error occurs
  354.      */
  355.     public void mark(int readAheadLimit) throws IOException {
  356.     if (readAheadLimit < 0) {
  357.         throw new IllegalArgumentException("Read-ahead limit < 0");
  358.     }
  359.     synchronized (lock) {
  360.         ensureOpen();
  361.         this.readAheadLimit = readAheadLimit;
  362.         markedChar = nextChar;
  363.     }
  364.     }
  365.  
  366.     /**
  367.      * Reset the stream to the most recent mark.
  368.      *
  369.      * @exception  IOException  If the stream has never been marked,
  370.      *                          or if the mark has been invalidated
  371.      */
  372.     public void reset() throws IOException {
  373.     synchronized (lock) {
  374.         ensureOpen();
  375.         if (markedChar < 0)
  376.         throw new IOException((markedChar == INVALIDATED)
  377.                       ? "Mark invalid"
  378.                       : "Stream not marked");
  379.         nextChar = markedChar;
  380.     }
  381.     }
  382.  
  383.     /**
  384.      * Close the stream.
  385.      *
  386.      * @exception  IOException  If an I/O error occurs
  387.      */
  388.     public void close() throws IOException {
  389.     synchronized (lock) {
  390.         if (in == null)
  391.         return;
  392.         in.close();
  393.         in = null;
  394.         cb = null;
  395.     }
  396.     }
  397.  
  398. }
  399.