• Java IO流 BufferedInputStream、BufferedOutputStream的基本使用


            BufferedInputStream、BufferedOutputStream的基本使用

      BufferedInputStream是FilterInputStream流的子类,FilterInputStream又是InputStream流的子类。一个BufferedInputStream为另一个输入流添加了功能,即缓冲输入和支持mark和reset方法的功能。当BufferedInputStream创建时,就会创建一个内部缓冲区数组。当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次有多个字节。mark操作会记住输入流中的一点,并且reset

    操作会导致从最近的mark操作之后读取的所有字节在从包含的输入流中取出新的字节之前重新读取。

      以下例子比较了FileInputStream和BufferedInputStream读取文件的效率,发现BufferedInputStream的效率还是要高很多,虽然两者都是一个字节一个字节的进行读取,但BufferedInputStream因为有一个内部缓冲数组。所以当它第一次从磁盘读取时,它就会突然从磁盘中读取很多字节进入缓冲区,然后再从缓冲区里面进行一个字节一个字节读取。经测试,它的读取效率比FileInputStream读取效率更高、读取数据所用的时间更少。FileInputStream的使用可参考https://www.cnblogs.com/jhtian/p/14110083.html

    测试中的文件如下:

      1 /*
      2  * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
      3  * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
      4  *
      5  *
      6  *
      7  *
      8  *
      9  *
     10  *
     11  *
     12  *
     13  *
     14  *
     15  *
     16  *
     17  *
     18  *
     19  *
     20  *
     21  *
     22  *
     23  *
     24  */
     25 
     26 package java.io;
     27 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
     28 
     29 /**
     30  * A <code>BufferedInputStream</code> adds
     31  * functionality to another input stream-namely,
     32  * the ability to buffer the input and to
     33  * support the <code>mark</code> and <code>reset</code>
     34  * methods. When  the <code>BufferedInputStream</code>
     35  * is created, an internal buffer array is
     36  * created. As bytes  from the stream are read
     37  * or skipped, the internal buffer is refilled
     38  * as necessary  from the contained input stream,
     39  * many bytes at a time. The <code>mark</code>
     40  * operation  remembers a point in the input
     41  * stream and the <code>reset</code> operation
     42  * causes all the  bytes read since the most
     43  * recent <code>mark</code> operation to be
     44  * reread before new bytes are  taken from
     45  * the contained input stream.
     46  *
     47  * @author  Arthur van Hoff
     48  * @since   JDK1.0
     49  */
     50 public
     51 class BufferedInputStream extends FilterInputStream {
     52 
     53     private static int DEFAULT_BUFFER_SIZE = 8192;
     54 
     55     /**
     56      * The maximum size of array to allocate.
     57      * Some VMs reserve some header words in an array.
     58      * Attempts to allocate larger arrays may result in
     59      * OutOfMemoryError: Requested array size exceeds VM limit
     60      */
     61     private static int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
     62 
     63     /**
     64      * The internal buffer array where the data is stored. When necessary,
     65      * it may be replaced by another array of
     66      * a different size.
     67      */
     68     protected volatile byte buf[];
     69 
     70     /**
     71      * Atomic updater to provide compareAndSet for buf. This is
     72      * necessary because closes can be asynchronous. We use nullness
     73      * of buf[] as primary indicator that this stream is closed. (The
     74      * "in" field is also nulled out on close.)
     75      */
     76     private static final
     77         AtomicReferenceFieldUpdater<BufferedInputStream, byte[]> bufUpdater =
     78         AtomicReferenceFieldUpdater.newUpdater
     79         (BufferedInputStream.class,  byte[].class, "buf");
     80 
     81     /**
     82      * The index one greater than the index of the last valid byte in
     83      * the buffer.
     84      * This value is always
     85      * in the range <code>0</code> through <code>buf.length</code>;
     86      * elements <code>buf[0]</code>  through <code>buf[count-1]
     87      * </code>contain buffered input data obtained
     88      * from the underlying  input stream.
     89      */
     90     protected int count;
     91 
     92     /**
     93      * The current position in the buffer. This is the index of the next
     94      * character to be read from the <code>buf</code> array.
     95      * <p>
     96      * This value is always in the range <code>0</code>
     97      * through <code>count</code>. If it is less
     98      * than <code>count</code>, then  <code>buf[pos]</code>
     99      * is the next byte to be supplied as input;
    100      * if it is equal to <code>count</code>, then
    101      * the  next <code>read</code> or <code>skip</code>
    102      * operation will require more bytes to be
    103      * read from the contained  input stream.
    104      *
    105      * @see     java.io.BufferedInputStream#buf
    106      */
    107     protected int pos;
    108 
    109     /**
    110      * The value of the <code>pos</code> field at the time the last
    111      * <code>mark</code> method was called.
    112      * <p>
    113      * This value is always
    114      * in the range <code>-1</code> through <code>pos</code>.
    115      * If there is no marked position in  the input
    116      * stream, this field is <code>-1</code>. If
    117      * there is a marked position in the input
    118      * stream,  then <code>buf[markpos]</code>
    119      * is the first byte to be supplied as input
    120      * after a <code>reset</code> operation. If
    121      * <code>markpos</code> is not <code>-1</code>,
    122      * then all bytes from positions <code>buf[markpos]</code>
    123      * through  <code>buf[pos-1]</code> must remain
    124      * in the buffer array (though they may be
    125      * moved to  another place in the buffer array,
    126      * with suitable adjustments to the values
    127      * of <code>count</code>,  <code>pos</code>,
    128      * and <code>markpos</code>); they may not
    129      * be discarded unless and until the difference
    130      * between <code>pos</code> and <code>markpos</code>
    131      * exceeds <code>marklimit</code>.
    132      *
    133      * @see     java.io.BufferedInputStream#mark(int)
    134      * @see     java.io.BufferedInputStream#pos
    135      */
    136     protected int markpos = -1;
    137 
    138     /**
    139      * The maximum read ahead allowed after a call to the
    140      * <code>mark</code> method before subsequent calls to the
    141      * <code>reset</code> method fail.
    142      * Whenever the difference between <code>pos</code>
    143      * and <code>markpos</code> exceeds <code>marklimit</code>,
    144      * then the  mark may be dropped by setting
    145      * <code>markpos</code> to <code>-1</code>.
    146      *
    147      * @see     java.io.BufferedInputStream#mark(int)
    148      * @see     java.io.BufferedInputStream#reset()
    149      */
    150     protected int marklimit;
    151 
    152     /**
    153      * Check to make sure that underlying input stream has not been
    154      * nulled out due to close; if not return it;
    155      */
    156     private InputStream getInIfOpen() throws IOException {
    157         InputStream input = in;
    158         if (input == null)
    159             throw new IOException("Stream closed");
    160         return input;
    161     }
    162 
    163     /**
    164      * Check to make sure that buffer has not been nulled out due to
    165      * close; if not return it;
    166      */
    167     private byte[] getBufIfOpen() throws IOException {
    168         byte[] buffer = buf;
    169         if (buffer == null)
    170             throw new IOException("Stream closed");
    171         return buffer;
    172     }
    173 
    174     /**
    175      * Creates a <code>BufferedInputStream</code>
    176      * and saves its  argument, the input stream
    177      * <code>in</code>, for later use. An internal
    178      * buffer array is created and  stored in <code>buf</code>.
    179      *
    180      * @param   in   the underlying input stream.
    181      */
    182     public BufferedInputStream(InputStream in) {
    183         this(in, DEFAULT_BUFFER_SIZE);
    184     }
    185 
    186     /**
    187      * Creates a <code>BufferedInputStream</code>
    188      * with the specified buffer size,
    189      * and saves its  argument, the input stream
    190      * <code>in</code>, for later use.  An internal
    191      * buffer array of length  <code>size</code>
    192      * is created and stored in <code>buf</code>.
    193      *
    194      * @param   in     the underlying input stream.
    195      * @param   size   the buffer size.
    196      * @exception IllegalArgumentException if {@code size <= 0}.
    197      */
    198     public BufferedInputStream(InputStream in, int size) {
    199         super(in);
    200         if (size <= 0) {
    201             throw new IllegalArgumentException("Buffer size <= 0");
    202         }
    203         buf = new byte[size];
    204     }
    205 
    206     /**
    207      * Fills the buffer with more data, taking into account
    208      * shuffling and other tricks for dealing with marks.
    209      * Assumes that it is being called by a synchronized method.
    210      * This method also assumes that all data has already been read in,
    211      * hence pos > count.
    212      */
    213     private void fill() throws IOException {
    214         byte[] buffer = getBufIfOpen();
    215         if (markpos < 0)
    216             pos = 0;            /* no mark: throw away the buffer */
    217         else if (pos >= buffer.length)  /* no room left in buffer */
    218             if (markpos > 0) {  /* can throw away early part of the buffer */
    219                 int sz = pos - markpos;
    220                 System.arraycopy(buffer, markpos, buffer, 0, sz);
    221                 pos = sz;
    222                 markpos = 0;
    223             } else if (buffer.length >= marklimit) {
    224                 markpos = -1;   /* buffer got too big, invalidate mark */
    225                 pos = 0;        /* drop buffer contents */
    226             } else if (buffer.length >= MAX_BUFFER_SIZE) {
    227                 throw new OutOfMemoryError("Required array size too large");
    228             } else {            /* grow buffer */
    229                 int nsz = (pos <= MAX_BUFFER_SIZE - pos) ?
    230                         pos * 2 : MAX_BUFFER_SIZE;
    231                 if (nsz > marklimit)
    232                     nsz = marklimit;
    233                 byte nbuf[] = new byte[nsz];
    234                 System.arraycopy(buffer, 0, nbuf, 0, pos);
    235                 if (!bufUpdater.compareAndSet(this, buffer, nbuf)) {
    236                     // Can't replace buf if there was an async close.
    237                     // Note: This would need to be changed if fill()
    238                     // is ever made accessible to multiple threads.
    239                     // But for now, the only way CAS can fail is via close.
    240                     // assert buf == null;
    241                     throw new IOException("Stream closed");
    242                 }
    243                 buffer = nbuf;
    244             }
    245         count = pos;
    246         int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
    247         if (n > 0)
    248             count = n + pos;
    249     }
    250 
    251     /**
    252      * See
    253      * the general contract of the <code>read</code>
    254      * method of <code>InputStream</code>.
    255      *
    256      * @return     the next byte of data, or <code>-1</code> if the end of the
    257      *             stream is reached.
    258      * @exception  IOException  if this input stream has been closed by
    259      *                          invoking its {@link #close()} method,
    260      *                          or an I/O error occurs.
    261      * @see        java.io.FilterInputStream#in
    262      */
    263     public synchronized int read() throws IOException {
    264         if (pos >= count) {
    265             fill();
    266             if (pos >= count)
    267                 return -1;
    268         }
    269         return getBufIfOpen()[pos++] & 0xff;
    270     }
    271 
    272     /**
    273      * Read characters into a portion of an array, reading from the underlying
    274      * stream at most once if necessary.
    275      */
    276     private int read1(byte[] b, int off, int len) throws IOException {
    277         int avail = count - pos;
    278         if (avail <= 0) {
    279             /* If the requested length is at least as large as the buffer, and
    280                if there is no mark/reset activity, do not bother to copy the
    281                bytes into the local buffer.  In this way buffered streams will
    282                cascade harmlessly. */
    283             if (len >= getBufIfOpen().length && markpos < 0) {
    284                 return getInIfOpen().read(b, off, len);
    285             }
    286             fill();
    287             avail = count - pos;
    288             if (avail <= 0) return -1;
    289         }
    290         int cnt = (avail < len) ? avail : len;
    291         System.arraycopy(getBufIfOpen(), pos, b, off, cnt);
    292         pos += cnt;
    293         return cnt;
    294     }
    295 
    296     /**
    297      * Reads bytes from this byte-input stream into the specified byte array,
    298      * starting at the given offset.
    299      *
    300      * <p> This method implements the general contract of the corresponding
    301      * <code>{@link InputStream#read(byte[], int, int) read}</code> method of
    302      * the <code>{@link InputStream}</code> class.  As an additional
    303      * convenience, it attempts to read as many bytes as possible by repeatedly
    304      * invoking the <code>read</code> method of the underlying stream.  This
    305      * iterated <code>read</code> continues until one of the following
    306      * conditions becomes true: <ul>
    307      *
    308      *   <li> The specified number of bytes have been read,
    309      *
    310      *   <li> The <code>read</code> method of the underlying stream returns
    311      *   <code>-1</code>, indicating end-of-file, or
    312      *
    313      *   <li> The <code>available</code> method of the underlying stream
    314      *   returns zero, indicating that further input requests would block.
    315      *
    316      * </ul> If the first <code>read</code> on the underlying stream returns
    317      * <code>-1</code> to indicate end-of-file then this method returns
    318      * <code>-1</code>.  Otherwise this method returns the number of bytes
    319      * actually read.
    320      *
    321      * <p> Subclasses of this class are encouraged, but not required, to
    322      * attempt to read as many bytes as possible in the same fashion.
    323      *
    324      * @param      b     destination buffer.
    325      * @param      off   offset at which to start storing bytes.
    326      * @param      len   maximum number of bytes to read.
    327      * @return     the number of bytes read, or <code>-1</code> if the end of
    328      *             the stream has been reached.
    329      * @exception  IOException  if this input stream has been closed by
    330      *                          invoking its {@link #close()} method,
    331      *                          or an I/O error occurs.
    332      */
    333     public synchronized int read(byte b[], int off, int len)
    334         throws IOException
    335     {
    336         getBufIfOpen(); // Check for closed stream
    337         if ((off | len | (off + len) | (b.length - (off + len))) < 0) {
    338             throw new IndexOutOfBoundsException();
    339         } else if (len == 0) {
    340             return 0;
    341         }
    342 
    343         int n = 0;
    344         for (;;) {
    345             int nread = read1(b, off + n, len - n);
    346             if (nread <= 0)
    347                 return (n == 0) ? nread : n;
    348             n += nread;
    349             if (n >= len)
    350                 return n;
    351             // if not closed but no bytes available, return
    352             InputStream input = in;
    353             if (input != null && input.available() <= 0)
    354                 return n;
    355         }
    356     }
    357 
    358     /**
    359      * See the general contract of the <code>skip</code>
    360      * method of <code>InputStream</code>.
    361      *
    362      * @exception  IOException  if the stream does not support seek,
    363      *                          or if this input stream has been closed by
    364      *                          invoking its {@link #close()} method, or an
    365      *                          I/O error occurs.
    366      */
    367     public synchronized long skip(long n) throws IOException {
    368         getBufIfOpen(); // Check for closed stream
    369         if (n <= 0) {
    370             return 0;
    371         }
    372         long avail = count - pos;
    373 
    374         if (avail <= 0) {
    375             // If no mark position set then don't keep in buffer
    376             if (markpos <0)
    377                 return getInIfOpen().skip(n);
    378 
    379             // Fill in buffer to save bytes for reset
    380             fill();
    381             avail = count - pos;
    382             if (avail <= 0)
    383                 return 0;
    384         }
    385 
    386         long skipped = (avail < n) ? avail : n;
    387         pos += skipped;
    388         return skipped;
    389     }
    390 
    391     /**
    392      * Returns an estimate of the number of bytes that can be read (or
    393      * skipped over) from this input stream without blocking by the next
    394      * invocation of a method for this input stream. The next invocation might be
    395      * the same thread or another thread.  A single read or skip of this
    396      * many bytes will not block, but may read or skip fewer bytes.
    397      * <p>
    398      * This method returns the sum of the number of bytes remaining to be read in
    399      * the buffer (<code>count&nbsp;- pos</code>) and the result of calling the
    400      * {@link java.io.FilterInputStream#in in}.available().
    401      *
    402      * @return     an estimate of the number of bytes that can be read (or skipped
    403      *             over) from this input stream without blocking.
    404      * @exception  IOException  if this input stream has been closed by
    405      *                          invoking its {@link #close()} method,
    406      *                          or an I/O error occurs.
    407      */
    408     public synchronized int available() throws IOException {
    409         int n = count - pos;
    410         int avail = getInIfOpen().available();
    411         return n > (Integer.MAX_VALUE - avail)
    412                     ? Integer.MAX_VALUE
    413                     : n + avail;
    414     }
    415 
    416     /**
    417      * See the general contract of the <code>mark</code>
    418      * method of <code>InputStream</code>.
    419      *
    420      * @param   readlimit   the maximum limit of bytes that can be read before
    421      *                      the mark position becomes invalid.
    422      * @see     java.io.BufferedInputStream#reset()
    423      */
    424     public synchronized void mark(int readlimit) {
    425         marklimit = readlimit;
    426         markpos = pos;
    427     }
    428 
    429     /**
    430      * See the general contract of the <code>reset</code>
    431      * method of <code>InputStream</code>.
    432      * <p>
    433      * If <code>markpos</code> is <code>-1</code>
    434      * (no mark has been set or the mark has been
    435      * invalidated), an <code>IOException</code>
    436      * is thrown. Otherwise, <code>pos</code> is
    437      * set equal to <code>markpos</code>.
    438      *
    439      * @exception  IOException  if this stream has not been marked or,
    440      *                  if the mark has been invalidated, or the stream
    441      *                  has been closed by invoking its {@link #close()}
    442      *                  method, or an I/O error occurs.
    443      * @see        java.io.BufferedInputStream#mark(int)
    444      */
    445     public synchronized void reset() throws IOException {
    446         getBufIfOpen(); // Cause exception if closed
    447         if (markpos < 0)
    448             throw new IOException("Resetting to invalid mark");
    449         pos = markpos;
    450     }
    451 
    452     /**
    453      * Tests if this input stream supports the <code>mark</code>
    454      * and <code>reset</code> methods. The <code>markSupported</code>
    455      * method of <code>BufferedInputStream</code> returns
    456      * <code>true</code>.
    457      *
    458      * @return  a <code>boolean</code> indicating if this stream type supports
    459      *          the <code>mark</code> and <code>reset</code> methods.
    460      * @see     java.io.InputStream#mark(int)
    461      * @see     java.io.InputStream#reset()
    462      */
    463     public boolean markSupported() {
    464         return true;
    465     }
    466 
    467     /**
    468      * Closes this input stream and releases any system resources
    469      * associated with the stream.
    470      * Once the stream has been closed, further read(), available(), reset(),
    471      * or skip() invocations will throw an IOException.
    472      * Closing a previously closed stream has no effect.
    473      *
    474      * @exception  IOException  if an I/O error occurs.
    475      */
    476     public void close() throws IOException {
    477         byte[] buffer;
    478         while ( (buffer = buf) != null) {
    479             if (bufUpdater.compareAndSet(this, buffer, null)) {
    480                 InputStream input = in;
    481                 in = null;
    482                 if (input != null)
    483                     input.close();
    484                 return;
    485             }
    486             // Else retry in case a new buf was CASed in fill()
    487         }
    488     }
    489 }
    BufferedInputStream.java

    测试代码:

    package com.tianjh.io.inputstream;
    
    import java.io.BufferedInputStream;
    import java.io.FileInputStream;
    import java.io.IOException;
    
    /**
     * Created on 2020/12/10
     * A BufferedInputStream为另一个输入流添加了功能,即缓冲输入和支持mark和reset方法的功能
     * BufferedInputStream创建时,就会创建一个内部缓冲区数组。当从流中读取或跳过字节时,内部缓
     * 冲区将根据需要从所包含的输入流中重新填充,一次有多个字节。mark操作会记住输入流中的一点,并
     * 且reset操作会导致从最近的mark操作之后读取的所有字节在从包含的输入流中取出新的字节之前重新
     * 读取
     **/
    public class BufferedInputStreamDemo {
        public static void main(String[] args) {
            // 1.FileInputStream的read方法读取
            try {
                // 使用字符串类型的文件名创建一个文件输入流对象来读取文件
                FileInputStream fileInputStream = new FileInputStream("D:/BufferedInputStream.java");
                // 获得遍历之前的时间
                long startTime = System.currentTimeMillis();
                int size;
                // read方法返回-1,表示文件结尾
                while ((size = fileInputStream.read()) != -1) {}
                // 关闭此输入流并释放与流相关联的任何系统资源
                fileInputStream.close();
                // 获得遍历所需要的时间
                long endTime = System.currentTimeMillis() - startTime;
                System.out.println("FileInputStream的read遍历文件所用时间为: "+endTime);
                // expected output: FileInputStream的read遍历文件所用时间为: 63
            } catch (IOException e) {
                e.printStackTrace();
            }
    
            // 2.BufferedInputStream的read方法读取
            try {
                // 使用字符串类型的文件名创建一个文件输入流对象来读取文件
                FileInputStream fileInputStream = new FileInputStream("D:/BufferedInputStream.java");
                BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
                // 获得遍历之前的时间
                long startTime = System.currentTimeMillis();
                int size;
                // read方法返回-1,表示文件结尾 BufferedInputStream的read方法也是一个字节一个字节读取,但是它因为有一个
                // 内部缓冲数组。所以当它第一次从磁盘读取时,它就会突然从磁盘中读取很多字节进入缓冲区,然后再从缓冲区里面进行
                // 一个字节一个字节读取。所以它的读取效率比FileInputStream读取效率更高
                while ((size = bufferedInputStream.read()) != -1) {}
                // 关闭此输入流并释放与流相关联的任何系统资源
                bufferedInputStream.close();
                fileInputStream.close();
                // 获得遍历所需要的时间
                long endTime = System.currentTimeMillis() - startTime;
                System.out.println("BufferedInputStream的read遍历文件所用时间为: "+endTime);
                // expected output: BufferedInputStream的read遍历文件所用时间为: 1
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    上述列子输出结果为:

      FileInputStream的read遍历文件所用时间为: 63
      BufferedInputStream的read遍历文件所用时间为: 1

    BufferedOutputStream它内部也有一个buffer(缓存),它的原理和BufferedInputStream流一样,当写数据时,可以进行批量的写数据。以下是做一个文件的拷贝Demo,实现先从指定文件 D:/BufferedInputStream.java 读取数据然后再把读取到的数据写入到指定文件 D:/BufferedOutputStream.java 中。

    package com.tianjh.io.outputstream;
    
    import java.io.*;
    
    /**
     * Created on 2020/12/10
     * BufferedOutputStream它内部有一个buffer(缓存),当写数据时,可以批量的写
     * 它的工作原理和BufferedInputStream是一样的
     * 实现先从指定文件 D:/BufferedInputStream.java 读取数据然后再把读取到的数据
     * 写入到指定文件  D:/BufferedOutputStream.java 中
     **/
    public class BufferedOutputStreamDemo {
        public static void main(String[] args) {
            // 1.BufferedInputStream的read方法读取字节
            // 2.BufferedOutputStream的write方法写入字节
            try {
                String sourceFile = "D:/BufferedInputStream.java";
                String targetFile = "D:/BufferedOutputStream.java";
                // 使用字符串类型的文件名创建一个文件输入流对象来读取文件
                FileInputStream fis = new FileInputStream(sourceFile);
                BufferedInputStream bis = new BufferedInputStream(fis);
                FileOutputStream fos = new FileOutputStream(targetFile);
                BufferedOutputStream bos = new BufferedOutputStream(fos);
    
                int readCount;
                byte[] readByte = new byte[256];
                while ((readCount = bis.read(readByte, 0, readByte.length)) != -1) {
                    bos.write(readByte, 0, readCount);
                }
                bis.close();
                bos.close();
                System.out.println("拷贝完成!");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    上述列子输出结果为:

      拷贝完成!

     拷贝成功之后的文件BufferedOutputStream和BufferedInputStream文件内容完全是一样的!

      1 /*
      2  * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
      3  * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
      4  *
      5  *
      6  *
      7  *
      8  *
      9  *
     10  *
     11  *
     12  *
     13  *
     14  *
     15  *
     16  *
     17  *
     18  *
     19  *
     20  *
     21  *
     22  *
     23  *
     24  */
     25 
     26 package java.io;
     27 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
     28 
     29 /**
     30  * A <code>BufferedInputStream</code> adds
     31  * functionality to another input stream-namely,
     32  * the ability to buffer the input and to
     33  * support the <code>mark</code> and <code>reset</code>
     34  * methods. When  the <code>BufferedInputStream</code>
     35  * is created, an internal buffer array is
     36  * created. As bytes  from the stream are read
     37  * or skipped, the internal buffer is refilled
     38  * as necessary  from the contained input stream,
     39  * many bytes at a time. The <code>mark</code>
     40  * operation  remembers a point in the input
     41  * stream and the <code>reset</code> operation
     42  * causes all the  bytes read since the most
     43  * recent <code>mark</code> operation to be
     44  * reread before new bytes are  taken from
     45  * the contained input stream.
     46  *
     47  * @author  Arthur van Hoff
     48  * @since   JDK1.0
     49  */
     50 public
     51 class BufferedInputStream extends FilterInputStream {
     52 
     53     private static int DEFAULT_BUFFER_SIZE = 8192;
     54 
     55     /**
     56      * The maximum size of array to allocate.
     57      * Some VMs reserve some header words in an array.
     58      * Attempts to allocate larger arrays may result in
     59      * OutOfMemoryError: Requested array size exceeds VM limit
     60      */
     61     private static int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
     62 
     63     /**
     64      * The internal buffer array where the data is stored. When necessary,
     65      * it may be replaced by another array of
     66      * a different size.
     67      */
     68     protected volatile byte buf[];
     69 
     70     /**
     71      * Atomic updater to provide compareAndSet for buf. This is
     72      * necessary because closes can be asynchronous. We use nullness
     73      * of buf[] as primary indicator that this stream is closed. (The
     74      * "in" field is also nulled out on close.)
     75      */
     76     private static final
     77         AtomicReferenceFieldUpdater<BufferedInputStream, byte[]> bufUpdater =
     78         AtomicReferenceFieldUpdater.newUpdater
     79         (BufferedInputStream.class,  byte[].class, "buf");
     80 
     81     /**
     82      * The index one greater than the index of the last valid byte in
     83      * the buffer.
     84      * This value is always
     85      * in the range <code>0</code> through <code>buf.length</code>;
     86      * elements <code>buf[0]</code>  through <code>buf[count-1]
     87      * </code>contain buffered input data obtained
     88      * from the underlying  input stream.
     89      */
     90     protected int count;
     91 
     92     /**
     93      * The current position in the buffer. This is the index of the next
     94      * character to be read from the <code>buf</code> array.
     95      * <p>
     96      * This value is always in the range <code>0</code>
     97      * through <code>count</code>. If it is less
     98      * than <code>count</code>, then  <code>buf[pos]</code>
     99      * is the next byte to be supplied as input;
    100      * if it is equal to <code>count</code>, then
    101      * the  next <code>read</code> or <code>skip</code>
    102      * operation will require more bytes to be
    103      * read from the contained  input stream.
    104      *
    105      * @see     java.io.BufferedInputStream#buf
    106      */
    107     protected int pos;
    108 
    109     /**
    110      * The value of the <code>pos</code> field at the time the last
    111      * <code>mark</code> method was called.
    112      * <p>
    113      * This value is always
    114      * in the range <code>-1</code> through <code>pos</code>.
    115      * If there is no marked position in  the input
    116      * stream, this field is <code>-1</code>. If
    117      * there is a marked position in the input
    118      * stream,  then <code>buf[markpos]</code>
    119      * is the first byte to be supplied as input
    120      * after a <code>reset</code> operation. If
    121      * <code>markpos</code> is not <code>-1</code>,
    122      * then all bytes from positions <code>buf[markpos]</code>
    123      * through  <code>buf[pos-1]</code> must remain
    124      * in the buffer array (though they may be
    125      * moved to  another place in the buffer array,
    126      * with suitable adjustments to the values
    127      * of <code>count</code>,  <code>pos</code>,
    128      * and <code>markpos</code>); they may not
    129      * be discarded unless and until the difference
    130      * between <code>pos</code> and <code>markpos</code>
    131      * exceeds <code>marklimit</code>.
    132      *
    133      * @see     java.io.BufferedInputStream#mark(int)
    134      * @see     java.io.BufferedInputStream#pos
    135      */
    136     protected int markpos = -1;
    137 
    138     /**
    139      * The maximum read ahead allowed after a call to the
    140      * <code>mark</code> method before subsequent calls to the
    141      * <code>reset</code> method fail.
    142      * Whenever the difference between <code>pos</code>
    143      * and <code>markpos</code> exceeds <code>marklimit</code>,
    144      * then the  mark may be dropped by setting
    145      * <code>markpos</code> to <code>-1</code>.
    146      *
    147      * @see     java.io.BufferedInputStream#mark(int)
    148      * @see     java.io.BufferedInputStream#reset()
    149      */
    150     protected int marklimit;
    151 
    152     /**
    153      * Check to make sure that underlying input stream has not been
    154      * nulled out due to close; if not return it;
    155      */
    156     private InputStream getInIfOpen() throws IOException {
    157         InputStream input = in;
    158         if (input == null)
    159             throw new IOException("Stream closed");
    160         return input;
    161     }
    162 
    163     /**
    164      * Check to make sure that buffer has not been nulled out due to
    165      * close; if not return it;
    166      */
    167     private byte[] getBufIfOpen() throws IOException {
    168         byte[] buffer = buf;
    169         if (buffer == null)
    170             throw new IOException("Stream closed");
    171         return buffer;
    172     }
    173 
    174     /**
    175      * Creates a <code>BufferedInputStream</code>
    176      * and saves its  argument, the input stream
    177      * <code>in</code>, for later use. An internal
    178      * buffer array is created and  stored in <code>buf</code>.
    179      *
    180      * @param   in   the underlying input stream.
    181      */
    182     public BufferedInputStream(InputStream in) {
    183         this(in, DEFAULT_BUFFER_SIZE);
    184     }
    185 
    186     /**
    187      * Creates a <code>BufferedInputStream</code>
    188      * with the specified buffer size,
    189      * and saves its  argument, the input stream
    190      * <code>in</code>, for later use.  An internal
    191      * buffer array of length  <code>size</code>
    192      * is created and stored in <code>buf</code>.
    193      *
    194      * @param   in     the underlying input stream.
    195      * @param   size   the buffer size.
    196      * @exception IllegalArgumentException if {@code size <= 0}.
    197      */
    198     public BufferedInputStream(InputStream in, int size) {
    199         super(in);
    200         if (size <= 0) {
    201             throw new IllegalArgumentException("Buffer size <= 0");
    202         }
    203         buf = new byte[size];
    204     }
    205 
    206     /**
    207      * Fills the buffer with more data, taking into account
    208      * shuffling and other tricks for dealing with marks.
    209      * Assumes that it is being called by a synchronized method.
    210      * This method also assumes that all data has already been read in,
    211      * hence pos > count.
    212      */
    213     private void fill() throws IOException {
    214         byte[] buffer = getBufIfOpen();
    215         if (markpos < 0)
    216             pos = 0;            /* no mark: throw away the buffer */
    217         else if (pos >= buffer.length)  /* no room left in buffer */
    218             if (markpos > 0) {  /* can throw away early part of the buffer */
    219                 int sz = pos - markpos;
    220                 System.arraycopy(buffer, markpos, buffer, 0, sz);
    221                 pos = sz;
    222                 markpos = 0;
    223             } else if (buffer.length >= marklimit) {
    224                 markpos = -1;   /* buffer got too big, invalidate mark */
    225                 pos = 0;        /* drop buffer contents */
    226             } else if (buffer.length >= MAX_BUFFER_SIZE) {
    227                 throw new OutOfMemoryError("Required array size too large");
    228             } else {            /* grow buffer */
    229                 int nsz = (pos <= MAX_BUFFER_SIZE - pos) ?
    230                         pos * 2 : MAX_BUFFER_SIZE;
    231                 if (nsz > marklimit)
    232                     nsz = marklimit;
    233                 byte nbuf[] = new byte[nsz];
    234                 System.arraycopy(buffer, 0, nbuf, 0, pos);
    235                 if (!bufUpdater.compareAndSet(this, buffer, nbuf)) {
    236                     // Can't replace buf if there was an async close.
    237                     // Note: This would need to be changed if fill()
    238                     // is ever made accessible to multiple threads.
    239                     // But for now, the only way CAS can fail is via close.
    240                     // assert buf == null;
    241                     throw new IOException("Stream closed");
    242                 }
    243                 buffer = nbuf;
    244             }
    245         count = pos;
    246         int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
    247         if (n > 0)
    248             count = n + pos;
    249     }
    250 
    251     /**
    252      * See
    253      * the general contract of the <code>read</code>
    254      * method of <code>InputStream</code>.
    255      *
    256      * @return     the next byte of data, or <code>-1</code> if the end of the
    257      *             stream is reached.
    258      * @exception  IOException  if this input stream has been closed by
    259      *                          invoking its {@link #close()} method,
    260      *                          or an I/O error occurs.
    261      * @see        java.io.FilterInputStream#in
    262      */
    263     public synchronized int read() throws IOException {
    264         if (pos >= count) {
    265             fill();
    266             if (pos >= count)
    267                 return -1;
    268         }
    269         return getBufIfOpen()[pos++] & 0xff;
    270     }
    271 
    272     /**
    273      * Read characters into a portion of an array, reading from the underlying
    274      * stream at most once if necessary.
    275      */
    276     private int read1(byte[] b, int off, int len) throws IOException {
    277         int avail = count - pos;
    278         if (avail <= 0) {
    279             /* If the requested length is at least as large as the buffer, and
    280                if there is no mark/reset activity, do not bother to copy the
    281                bytes into the local buffer.  In this way buffered streams will
    282                cascade harmlessly. */
    283             if (len >= getBufIfOpen().length && markpos < 0) {
    284                 return getInIfOpen().read(b, off, len);
    285             }
    286             fill();
    287             avail = count - pos;
    288             if (avail <= 0) return -1;
    289         }
    290         int cnt = (avail < len) ? avail : len;
    291         System.arraycopy(getBufIfOpen(), pos, b, off, cnt);
    292         pos += cnt;
    293         return cnt;
    294     }
    295 
    296     /**
    297      * Reads bytes from this byte-input stream into the specified byte array,
    298      * starting at the given offset.
    299      *
    300      * <p> This method implements the general contract of the corresponding
    301      * <code>{@link InputStream#read(byte[], int, int) read}</code> method of
    302      * the <code>{@link InputStream}</code> class.  As an additional
    303      * convenience, it attempts to read as many bytes as possible by repeatedly
    304      * invoking the <code>read</code> method of the underlying stream.  This
    305      * iterated <code>read</code> continues until one of the following
    306      * conditions becomes true: <ul>
    307      *
    308      *   <li> The specified number of bytes have been read,
    309      *
    310      *   <li> The <code>read</code> method of the underlying stream returns
    311      *   <code>-1</code>, indicating end-of-file, or
    312      *
    313      *   <li> The <code>available</code> method of the underlying stream
    314      *   returns zero, indicating that further input requests would block.
    315      *
    316      * </ul> If the first <code>read</code> on the underlying stream returns
    317      * <code>-1</code> to indicate end-of-file then this method returns
    318      * <code>-1</code>.  Otherwise this method returns the number of bytes
    319      * actually read.
    320      *
    321      * <p> Subclasses of this class are encouraged, but not required, to
    322      * attempt to read as many bytes as possible in the same fashion.
    323      *
    324      * @param      b     destination buffer.
    325      * @param      off   offset at which to start storing bytes.
    326      * @param      len   maximum number of bytes to read.
    327      * @return     the number of bytes read, or <code>-1</code> if the end of
    328      *             the stream has been reached.
    329      * @exception  IOException  if this input stream has been closed by
    330      *                          invoking its {@link #close()} method,
    331      *                          or an I/O error occurs.
    332      */
    333     public synchronized int read(byte b[], int off, int len)
    334         throws IOException
    335     {
    336         getBufIfOpen(); // Check for closed stream
    337         if ((off | len | (off + len) | (b.length - (off + len))) < 0) {
    338             throw new IndexOutOfBoundsException();
    339         } else if (len == 0) {
    340             return 0;
    341         }
    342 
    343         int n = 0;
    344         for (;;) {
    345             int nread = read1(b, off + n, len - n);
    346             if (nread <= 0)
    347                 return (n == 0) ? nread : n;
    348             n += nread;
    349             if (n >= len)
    350                 return n;
    351             // if not closed but no bytes available, return
    352             InputStream input = in;
    353             if (input != null && input.available() <= 0)
    354                 return n;
    355         }
    356     }
    357 
    358     /**
    359      * See the general contract of the <code>skip</code>
    360      * method of <code>InputStream</code>.
    361      *
    362      * @exception  IOException  if the stream does not support seek,
    363      *                          or if this input stream has been closed by
    364      *                          invoking its {@link #close()} method, or an
    365      *                          I/O error occurs.
    366      */
    367     public synchronized long skip(long n) throws IOException {
    368         getBufIfOpen(); // Check for closed stream
    369         if (n <= 0) {
    370             return 0;
    371         }
    372         long avail = count - pos;
    373 
    374         if (avail <= 0) {
    375             // If no mark position set then don't keep in buffer
    376             if (markpos <0)
    377                 return getInIfOpen().skip(n);
    378 
    379             // Fill in buffer to save bytes for reset
    380             fill();
    381             avail = count - pos;
    382             if (avail <= 0)
    383                 return 0;
    384         }
    385 
    386         long skipped = (avail < n) ? avail : n;
    387         pos += skipped;
    388         return skipped;
    389     }
    390 
    391     /**
    392      * Returns an estimate of the number of bytes that can be read (or
    393      * skipped over) from this input stream without blocking by the next
    394      * invocation of a method for this input stream. The next invocation might be
    395      * the same thread or another thread.  A single read or skip of this
    396      * many bytes will not block, but may read or skip fewer bytes.
    397      * <p>
    398      * This method returns the sum of the number of bytes remaining to be read in
    399      * the buffer (<code>count&nbsp;- pos</code>) and the result of calling the
    400      * {@link java.io.FilterInputStream#in in}.available().
    401      *
    402      * @return     an estimate of the number of bytes that can be read (or skipped
    403      *             over) from this input stream without blocking.
    404      * @exception  IOException  if this input stream has been closed by
    405      *                          invoking its {@link #close()} method,
    406      *                          or an I/O error occurs.
    407      */
    408     public synchronized int available() throws IOException {
    409         int n = count - pos;
    410         int avail = getInIfOpen().available();
    411         return n > (Integer.MAX_VALUE - avail)
    412                     ? Integer.MAX_VALUE
    413                     : n + avail;
    414     }
    415 
    416     /**
    417      * See the general contract of the <code>mark</code>
    418      * method of <code>InputStream</code>.
    419      *
    420      * @param   readlimit   the maximum limit of bytes that can be read before
    421      *                      the mark position becomes invalid.
    422      * @see     java.io.BufferedInputStream#reset()
    423      */
    424     public synchronized void mark(int readlimit) {
    425         marklimit = readlimit;
    426         markpos = pos;
    427     }
    428 
    429     /**
    430      * See the general contract of the <code>reset</code>
    431      * method of <code>InputStream</code>.
    432      * <p>
    433      * If <code>markpos</code> is <code>-1</code>
    434      * (no mark has been set or the mark has been
    435      * invalidated), an <code>IOException</code>
    436      * is thrown. Otherwise, <code>pos</code> is
    437      * set equal to <code>markpos</code>.
    438      *
    439      * @exception  IOException  if this stream has not been marked or,
    440      *                  if the mark has been invalidated, or the stream
    441      *                  has been closed by invoking its {@link #close()}
    442      *                  method, or an I/O error occurs.
    443      * @see        java.io.BufferedInputStream#mark(int)
    444      */
    445     public synchronized void reset() throws IOException {
    446         getBufIfOpen(); // Cause exception if closed
    447         if (markpos < 0)
    448             throw new IOException("Resetting to invalid mark");
    449         pos = markpos;
    450     }
    451 
    452     /**
    453      * Tests if this input stream supports the <code>mark</code>
    454      * and <code>reset</code> methods. The <code>markSupported</code>
    455      * method of <code>BufferedInputStream</code> returns
    456      * <code>true</code>.
    457      *
    458      * @return  a <code>boolean</code> indicating if this stream type supports
    459      *          the <code>mark</code> and <code>reset</code> methods.
    460      * @see     java.io.InputStream#mark(int)
    461      * @see     java.io.InputStream#reset()
    462      */
    463     public boolean markSupported() {
    464         return true;
    465     }
    466 
    467     /**
    468      * Closes this input stream and releases any system resources
    469      * associated with the stream.
    470      * Once the stream has been closed, further read(), available(), reset(),
    471      * or skip() invocations will throw an IOException.
    472      * Closing a previously closed stream has no effect.
    473      *
    474      * @exception  IOException  if an I/O error occurs.
    475      */
    476     public void close() throws IOException {
    477         byte[] buffer;
    478         while ( (buffer = buf) != null) {
    479             if (bufUpdater.compareAndSet(this, buffer, null)) {
    480                 InputStream input = in;
    481                 in = null;
    482                 if (input != null)
    483                     input.close();
    484                 return;
    485             }
    486             // Else retry in case a new buf was CASed in fill()
    487         }
    488     }
    489 }
    BufferedOutputStream.java
  • 相关阅读:
    函数传参的方式
    统计一个文本中单词频次最高的 10 个单词?
    统计一个文本中单词频次最高的 10 个单词?
    python每日练习0801
    关键字驱动小练习
    Fiddler抓包从入门到不放弃
    pycharm2019.1.3激活方法--激活码可以用到2089年
    Selenium+Python调Chrome浏览器时报Traceback (most recent call last): File "C:/Users/EDZ/Desktop/selenium_demo/demo001.py", line 12, in <module>
    JMeter服务端压测,人人都会的小白版本
    XShell命令大全
  • 原文地址:https://www.cnblogs.com/jhtian/p/14115355.html
Copyright © 2020-2023  润新知