home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgLangD.iso / VCAFE.3.0A / Main.bin / BufferedReader.java < prev    next >
Text File  |  1998-09-22  |  11KB  |  376 lines

  1. /*
  2.  * @(#)BufferedReader.java    1.12 98/07/01
  3.  *
  4.  * Copyright 1995-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.12, 98/07/01
  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.      * @return     A String containing the contents of the line, not including
  210.      *             any line-termination characters, or null if the end of the
  211.      *             stream has been reached
  212.      *
  213.      * @exception  IOException  If an I/O error occurs
  214.      */
  215.     public String readLine() throws IOException {
  216.     StringBuffer s = new StringBuffer(defaultExpectedLineLength);
  217.     synchronized (lock) {
  218.         ensureOpen();
  219.  
  220.     bufferLoop:
  221.         for (;;) {
  222.  
  223.         if (nextChar >= nChars)
  224.             fill();
  225.         if (nextChar >= nChars) { /* EOF */
  226.             if (s.length() > 0)
  227.             return s.toString();
  228.             else
  229.             return null;
  230.         }
  231.         boolean eol = false;
  232.         char c = 0;
  233.         int i;
  234.  
  235.         charLoop:
  236.         for (i = nextChar; i < nChars; i++) {
  237.             c = cb[i];
  238.             if ((c == '\n') || (c == '\r')) {
  239.             eol = true;
  240.             break charLoop;
  241.             }
  242.         }
  243.         s.append(cb, nextChar, i - nextChar);
  244.         nextChar = i;
  245.  
  246.         if (eol) {
  247.             nextChar++;
  248.             if (c == '\r') {
  249.             if (nextChar >= nChars)
  250.                 fill();
  251.             if ((nextChar < nChars) && (cb[nextChar] == '\n'))
  252.                 nextChar++;
  253.             }
  254.             break bufferLoop;
  255.         }
  256.         }
  257.     }
  258.  
  259.     return s.toString();
  260.     }
  261.  
  262.     /**
  263.      * Skip characters.
  264.      *
  265.      * @param  n  The number of characters to skip
  266.      *
  267.      * @return    The number of characters actually skipped
  268.      *
  269.      * @exception  IOException  If an I/O error occurs
  270.      */
  271.     public long skip(long n) throws IOException {
  272.     synchronized (lock) {
  273.         ensureOpen();
  274.         long r = n;
  275.         while (r > 0) {
  276.         if (nextChar >= nChars)
  277.             fill();
  278.         if (nextChar >= nChars)    /* EOF */
  279.             break;
  280.         long d = nChars - nextChar;
  281.         if (r <= d) {
  282.             nextChar += r;
  283.             r = 0;
  284.             break;
  285.         }
  286.         else {
  287.             r -= d;
  288.             nextChar = nChars;
  289.         }
  290.         }
  291.         return n - r;
  292.     }
  293.     }
  294.  
  295.     /**
  296.      * Tell whether this stream is ready to be read.  A buffered character
  297.      * stream is ready if the buffer is not empty, or if the underlying
  298.      * character stream is ready.
  299.      *
  300.      * @exception  IOException  If an I/O error occurs
  301.      */
  302.     public boolean ready() throws IOException {
  303.     synchronized (lock) {
  304.         ensureOpen();
  305.         return (nextChar < nChars) || in.ready();
  306.     }
  307.     }
  308.  
  309.     /**
  310.      * Tell whether this stream supports the mark() operation, which it does.
  311.      */
  312.     public boolean markSupported() {
  313.     return true;
  314.     }
  315.  
  316.     /**
  317.      * Mark the present position in the stream.  Subsequent calls to reset()
  318.      * will attempt to reposition the stream to this point.
  319.      *
  320.      * @param readAheadLimit   Limit on the number of characters that may be
  321.      *                         read while still preserving the mark.  After
  322.      *                         reading this many characters, attempting to
  323.      *                         reset the stream may fail.  A limit value larger
  324.      *                         than the size of the input buffer will cause a
  325.      *                         new buffer to be allocated whose size is no
  326.      *                         smaller than limit.  Therefore large values
  327.      *                         should be used with care.
  328.      *
  329.      * @exception  IllegalArgumentException  If readAheadLimit is < 0
  330.      * @exception  IOException  If an I/O error occurs
  331.      */
  332.     public void mark(int readAheadLimit) throws IOException {
  333.     if (readAheadLimit < 0) {
  334.         throw new IllegalArgumentException("Read-ahead limit < 0");
  335.     }
  336.     synchronized (lock) {
  337.         ensureOpen();
  338.         this.readAheadLimit = readAheadLimit;
  339.         markedChar = nextChar;
  340.     }
  341.     }
  342.  
  343.     /**
  344.      * Reset the stream to the most recent mark.
  345.      *
  346.      * @exception  IOException  If the stream has never been marked,
  347.      *                          or if the mark has been invalidated
  348.      */
  349.     public void reset() throws IOException {
  350.     synchronized (lock) {
  351.         ensureOpen();
  352.         if (markedChar < 0)
  353.         throw new IOException((markedChar == INVALIDATED)
  354.                       ? "Mark invalid"
  355.                       : "Stream not marked");
  356.         nextChar = markedChar;
  357.     }
  358.     }
  359.  
  360.     /**
  361.      * Close the stream.
  362.      *
  363.      * @exception  IOException  If an I/O error occurs
  364.      */
  365.     public void close() throws IOException {
  366.     synchronized (lock) {
  367.         if (in == null)
  368.         return;
  369.         in.close();
  370.         in = null;
  371.         cb = null;
  372.     }
  373.     }
  374.  
  375. }
  376.