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

  1. /*
  2.  * @(#)BufferedInputStream.java    1.31 98/03/18
  3.  *
  4.  * Copyright 1994-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.  * The class implements a buffered input stream. By setting up such 
  19.  * an input stream, an application can read bytes from a stream 
  20.  * without necessarily causing a call to the underlying system for 
  21.  * each byte read. The data is read by blocks into a buffer; 
  22.  * subsequent reads can access the data directly from the buffer. 
  23.  *
  24.  * @author  Arthur van Hoff
  25.  * @version 1.31, 03/18/98
  26.  * @since   JDK1.0
  27.  */
  28. public
  29. class BufferedInputStream extends FilterInputStream {
  30.  
  31.     private static int defaultBufferSize = 2048;
  32.  
  33.     /**
  34.      * The buffer where data is stored. 
  35.      */
  36.     protected byte buf[];
  37.  
  38.     /**
  39.      * The index one greater than the index of the last valid byte in 
  40.      * the buffer. 
  41.      */
  42.     protected int count;
  43.  
  44.     /**
  45.      * The current position in the buffer. This is the index of the next 
  46.      * character to be read from the <code>buf</code> array. 
  47.      *
  48.      * @see     java.io.BufferedInputStream#buf
  49.      */
  50.     protected int pos;
  51.     
  52.     /**
  53.      * The value of the <code>pos</code> field at the time the last 
  54.      * <code>mark</code> method was called. The value of this field is 
  55.      * <code>-1</code> if there is no current mark. 
  56.      *
  57.      * @see     java.io.BufferedInputStream#mark(int)
  58.      * @see     java.io.BufferedInputStream#pos
  59.      */
  60.     protected int markpos = -1;
  61.  
  62.     /**
  63.      * The maximum read ahead allowed after a call to the 
  64.      * <code>mark</code> method before subsequent calls to the 
  65.      * <code>reset</code> method fail. 
  66.      *
  67.      * @see     java.io.BufferedInputStream#mark(int)
  68.      * @see     java.io.BufferedInputStream#reset()
  69.      */
  70.     protected int marklimit;
  71.  
  72.     /**
  73.      * Check to make sure that this stream has not been closed
  74.      */
  75.     private void ensureOpen() throws IOException {
  76.     if (in == null)
  77.         throw new IOException("Stream closed");
  78.     }
  79.  
  80.     /**
  81.      * Creates a new buffered input stream to read data from the 
  82.      * specified input stream with the default buffer size. 
  83.      *
  84.      * @param   in   the underlying input stream.
  85.      */
  86.     public BufferedInputStream(InputStream in) {
  87.     this(in, defaultBufferSize);
  88.     }
  89.  
  90.     /**
  91.      * Creates a new buffered input stream to read data from the 
  92.      * specified input stream with the specified buffer size. 
  93.      *
  94.      * @param   in     the underlying input stream.
  95.      * @param   size   the buffer size.
  96.      */
  97.     public BufferedInputStream(InputStream in, int size) {
  98.     super(in);
  99.     buf = new byte[size];
  100.     }
  101.  
  102.     /**
  103.      * Fills the buffer with more data, taking into account
  104.      * shuffling and other tricks for dealing with marks.
  105.      * Assumes that it is being called by a synchronized method.
  106.      * This method also assumes that all data has already been read in,
  107.      * hence pos > count.
  108.      */
  109.     private void fill() throws IOException {
  110.     if (markpos < 0)
  111.         pos = 0;        /* no mark: throw away the buffer */
  112.     else if (pos >= buf.length)    /* no room left in buffer */
  113.         if (markpos > 0) {    /* can throw away early part of the buffer */
  114.         int sz = pos - markpos;
  115.         System.arraycopy(buf, markpos, buf, 0, sz);
  116.         pos = sz;
  117.         markpos = 0;
  118.         } else if (buf.length >= marklimit) {
  119.         markpos = -1;    /* buffer got too big, invalidate mark */
  120.         pos = 0;    /* drop buffer contents */
  121.         } else {        /* grow buffer */
  122.         int nsz = pos * 2;
  123.         if (nsz > marklimit)
  124.             nsz = marklimit;
  125.         byte nbuf[] = new byte[nsz];
  126.         System.arraycopy(buf, 0, nbuf, 0, pos);
  127.         buf = nbuf;
  128.         }
  129.         count = pos;
  130.     int n = in.read(buf, pos, buf.length - pos);
  131.         if (n > 0)
  132.             count = n + pos;
  133.     }
  134.  
  135.     /**
  136.      * Reads the next byte of data from this buffered input stream. The 
  137.      * value byte is returned as an <code>int</code> in the range 
  138.      * <code>0</code> to <code>255</code>. If no byte is available 
  139.      * because the end of the stream has been reached, the value 
  140.      * <code>-1</code> is returned. This method blocks until input data 
  141.      * is available, the end of the stream is detected, or an exception 
  142.      * is thrown. 
  143.      * <p>
  144.      * The <code>read</code> method of <code>BufferedInputStream</code> 
  145.      * returns the next byte of data from its buffer if the buffer is not 
  146.      * empty. Otherwise, it refills the buffer from the underlying input 
  147.      * stream and returns the next character, if the underlying stream 
  148.      * has not returned an end-of-stream indicator. 
  149.      *
  150.      * @return     the next byte of data, or <code>-1</code> if the end of the
  151.      *             stream is reached.
  152.      * @exception  IOException  if an I/O error occurs.
  153.      * @see        java.io.FilterInputStream#in
  154.      */
  155.     public synchronized int read() throws IOException {
  156.         ensureOpen();
  157.     if (pos >= count) {
  158.         fill();
  159.         if (pos >= count)
  160.         return -1;
  161.     }
  162.     return buf[pos++] & 0xff;
  163.     }
  164.  
  165.     /**
  166.      * Reads bytes into a portion of an array.  This method will block until
  167.      * some input is available, an I/O error occurs, or the end of the stream
  168.      * is reached.
  169.      *
  170.      * <p> If this stream's buffer is not empty, bytes are copied from it into
  171.      * the array argument.  Otherwise, the buffer is refilled from the
  172.      * underlying input stream and, unless the stream returns an end-of-stream
  173.      * indication, the array argument is filled with characters from the
  174.      * newly-filled buffer.
  175.      *
  176.      * <p> As an optimization, if the buffer is empty, the mark is not valid,
  177.      * and <code>len</code> is at least as large as the buffer, then this
  178.      * method will read directly from the underlying stream into the given
  179.      * array.  Thus redundant <code>BufferedInputStream</code>s will not copy
  180.      * data unnecessarily.
  181.      *
  182.      * @param      b     destination buffer.
  183.      * @param      off   offset at which to start storing bytes.
  184.      * @param      len   maximum number of bytes to read.
  185.      * @return     the number of bytes read, or <code>-1</code> if the end of
  186.      *             the stream has been reached.
  187.      * @exception  IOException  if an I/O error occurs.
  188.      */
  189.     public synchronized int read(byte b[], int off, int len) throws IOException {
  190.         ensureOpen();
  191.     int avail = count - pos;
  192.     if (avail <= 0) {
  193.         /* If the requested length is larger than the buffer, and if there
  194.            is no mark/reset activity, do not bother to copy the bytes into
  195.            the local buffer.  In this way buffered streams will cascade
  196.            harmlessly. */
  197.         if (len >= buf.length && markpos < 0) {
  198.         return in.read(b, off, len);
  199.         }
  200.         fill();
  201.         avail = count - pos;
  202.         if (avail <= 0)
  203.         return -1;
  204.     }
  205.     int cnt = (avail < len) ? avail : len;
  206.     System.arraycopy(buf, pos, b, off, cnt);
  207.     pos += cnt;
  208.     return cnt;
  209.     }
  210.  
  211.     /**
  212.      * Skips over and discards <code>n</code> bytes of data from the 
  213.      * input stream. The <code>skip</code> method may, for a variety of 
  214.      * reasons, end up skipping over some smaller number of bytes, 
  215.      * possibly zero. The actual number of bytes skipped is returned. 
  216.      * <p>
  217.      * If the buffer is not empty, then this method skips up to <code>n</code>
  218.      * bytes but does not refill the buffer.  If the buffer is empty and the
  219.      * mark is valid, then the buffer is filled once and then treated as in the
  220.      * previous case.  If the buffer is empty and the mark is not valid, then
  221.      * the <code>skip</code> method of the underlying input stream is invoked
  222.      * directly to skip up to <code>n</code> bytes.
  223.      *
  224.      * @param      n   the number of bytes to be skipped.
  225.      * @return     the actual number of bytes skipped.
  226.      * @exception  IOException  if an I/O error occurs.
  227.      */
  228.     public synchronized long skip(long n) throws IOException {
  229.         ensureOpen();
  230.     if (n <= 0) {
  231.         return 0;
  232.     }
  233.     long avail = count - pos;
  234.      
  235.         if (avail <= 0) {
  236.             // If no mark position set then don't keep in buffer
  237.             if (markpos <0) 
  238.                 return in.skip(n);
  239.             
  240.             // Fill in buffer to save bytes for reset
  241.             fill();
  242.             avail = count - pos;
  243.             if (avail <= 0)
  244.                 return 0;
  245.         }
  246.         
  247.         long skipped = (avail < n) ? avail : n;
  248.         pos += skipped;
  249.         return skipped;
  250.     }
  251.  
  252.     /**
  253.      * Returns the number of bytes that can be read from this input 
  254.      * stream without blocking. 
  255.      * <p>
  256.      * The <code>available</code> method of 
  257.      * <code>BufferedInputStream</code> returns the sum of the the number 
  258.      * of bytes remaining to be read in the buffer 
  259.      * (<code>count - pos</code>) 
  260.      * and the result of calling the <code>available</code> method of the 
  261.      * underlying input stream. 
  262.      *
  263.      * @return     the number of bytes that can be read from this input
  264.      *             stream without blocking.
  265.      * @exception  IOException  if an I/O error occurs.
  266.      * @see        java.io.FilterInputStream#in
  267.      */
  268.     public synchronized int available() throws IOException {
  269.         ensureOpen();
  270.     return (count - pos) + in.available();
  271.     }
  272.  
  273.     /**
  274.      * Marks the current position in this input stream. A subsequent 
  275.      * call to the <code>reset</code> method repositions the stream at 
  276.      * the last marked position so that subsequent reads re-read the same 
  277.      * bytes. 
  278.      * <p>
  279.      * The <code>readlimit</code> argument tells the input stream to 
  280.      * allow that many bytes to be read before the mark position gets 
  281.      * invalidated. 
  282.      *
  283.      * @param   readlimit   the maximum limit of bytes that can be read before
  284.      *                      the mark position becomes invalid.
  285.      * @see     java.io.BufferedInputStream#reset()
  286.      */
  287.     public synchronized void mark(int readlimit) {
  288.     marklimit = readlimit;
  289.     markpos = pos;
  290.     }
  291.  
  292.     /**
  293.      * Repositions this stream to the position at the time the 
  294.      * <code>mark</code> method was last called on this input stream. 
  295.      * <p>
  296.      * If the stream has not been marked, or if the mark has been invalidated,
  297.      * an IOException is thrown. Stream marks are intended to be used in
  298.      * situations where you need to read ahead a little to see what's in
  299.      * the stream. Often this is most easily done by invoking some
  300.      * general parser. If the stream is of the type handled by the
  301.      * parser, it just chugs along happily. If the stream is not of
  302.      * that type, the parser should toss an exception when it fails. If an
  303.      * exception gets tossed within readlimit bytes, the parser will allow the
  304.      * outer code to reset the stream and to try another parser.
  305.      *
  306.      * @exception  IOException  if this stream has not been marked or
  307.      *               if the mark has been invalidated.
  308.      * @see        java.io.BufferedInputStream#mark(int)
  309.      */
  310.     public synchronized void reset() throws IOException {
  311.         ensureOpen();
  312.     if (markpos < 0)
  313.         throw new IOException("Resetting to invalid mark");
  314.     pos = markpos;
  315.     }
  316.  
  317.     /**
  318.      * Tests if this input stream supports the <code>mark</code> 
  319.      * and <code>reset</code> methods. The <code>markSupported</code> 
  320.      * method of <code>BufferedInputStream</code> returns 
  321.      * <code>true</code>. 
  322.      *
  323.      * @return  a <code>boolean</code> indicating if this stream type supports
  324.      *          the <code>mark</code> and <code>reset</code> methods.
  325.      * @see     java.io.InputStream#mark(int)
  326.      * @see     java.io.InputStream#reset()
  327.      */
  328.     public boolean markSupported() {
  329.     return true;
  330.     }
  331.  
  332.     /**
  333.      * Closes this input stream and releases any system resources 
  334.      * associated with the stream. 
  335.      *
  336.      * @exception  IOException  if an I/O error occurs.
  337.      */
  338.     public synchronized void close() throws IOException {
  339.         if (in == null)
  340.             return;
  341.         in.close();
  342.         in = null;
  343.         buf = null;
  344.     }
  345. }
  346.