home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 November / Chip_1998-11_cd.bin / tema / Cafe / main.bin / BufferedReader.java < prev    next >
Text File  |  1997-05-20  |  11KB  |  384 lines

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