• Java IO 过滤流 BufferedInput/OutputStream


    Java IO 过滤流 BufferedInput/OutputStream

    @author ixenos

    概念


    BufferedInput/OutputStream是实现缓存的过滤流,他们分别是FilterInput/OutputStream的子类。

    BufferedInputStream工作流程


    stream-->buf--read buf-->I

    1.当一个BufferedInputStream被创建时,一个内部的缓冲区 byte[] buf = new byte[size] 也被建立,size默认是8192也就是默认创建一个8kb大小的缓存空间,

    工作时由内部方法fill()预先在缓冲区存储来自连接输入流的数据最终的数据来源由底层流决定,比如new FileInputStream("a.txt")来源就是a.txt,而我们过滤流的数据来源是节点流!

     1     private static int DEFAULT_BUFFER_SIZE = 8192; //默认缓冲数组长度大小,折合单位有8kb
     2     protected volatile byte buf[]; //底层维护的缓冲数组变量
     3 
     4     public BufferedInputStream(InputStream in) {
     5         this(in, DEFAULT_BUFFER_SIZE); //默认8192
     6     }
     7 
     8 
     9     public BufferedInputStream(InputStream in, int size) {
    10         super(in); //引用基类FilterInputStream的构造方法,基类有底层流变量
    11         if (size <= 0) {
    12             throw new IllegalArgumentException("Buffer size <= 0");
    13         }
    14         buf = new byte[size]; //初始化缓冲数组,指定大小为size
    15     }

    2.当BufferedInputStream的read方法被调用时,数据将从缓冲区中移出,而不是底层的输入流;

    3.当BufferedInputStream缓冲区数据用完时,他自动从底层输入流中补充数据

      read()源码分析:

        //返回下一个数据字节,如果到达流末尾则返回-1,数据流向返回值!
    1
    public synchronized int read() throws IOException { 2 if (pos >= count) { //当缓存指针等于或者超过count时,说明buf已满 3 fill(); //fill()从节点流中读取数据存放到buf缓冲区 4 if (pos >= count) 5 return -1; 6 } 7 return getBufIfOpen()[pos++] & 0xff; //得到非空buf缓冲当前索引为pos位置的一字节数据,pos++ 缓冲区指针移动一位 8 } 9 10 //getBufIfOpen对buf进行非空判断 11 private byte[] getBufIfOpen() throws IOException { 12 byte[] buffer = buf; //用一个引用变量引用buf 13 if (buffer == null) 14 throw new IOException("Stream closed"); 15 return buffer; //返回buffer,实质上指向buf 16 }

      read(byte[], int, int)源码分析 :

    //pos是起始/下一次读取buffer的位置,
    //markpos是最新一次已读取的位置,
    //count是缓冲数组被填充的大小-1(因为是作为index存在的,从0开始)
    //len是b要读取的最大字节数
      1     //返回读取的字节数,如果流到达末尾返回-1,数据流向b数组!
      2     public synchronized int read(byte b[], int off, int len)
      3         throws IOException
      4     {
      5         
      6         /*这里只做检查,流关闭则提前抛出,以避免拖到fill()中的getBufIfOpen()再抛出的情况
      7            private byte[] getBufIfOpen() throws IOException {
      8                byte[] buffer = buf; //引用传递,指向当前buf变量指向的内存
      9                if (buffer == null) //就为了这个非空判断而已
     10                    throw new IOException("Stream closed");
     11                return buffer; //这里返回值是没人接收的,方法结束抛弃局部变量buffer,不对buf造成影响
     12            }
     13          */
     14         getBufIfOpen(); // Check for closed stream 关闭流将抛出异常
     15         //指定数组的越界判断
     16         if ((off | len | (off + len) | (b.length - (off + len))) < 0) {
     17             throw new IndexOutOfBoundsException();
     18         } else if (len == 0) {
     19             return 0;
     20         }
     21 
     22         int n = 0;
     23         //循环写数据到b,直到buffer数据不足返回-1,此时nread已累加记录
     24         for (;;) {
     25             int nread = read1(b, off + n, len - n);//读缓冲区数据到b
     26             if (nread <= 0)
     27                 return (n == 0) ? nread : n;
     28             n += nread;
     29             //读完指定长度时返回
     30             if (n >= len)
     31                 return n;
     32             // if not closed but no bytes available, return
     33             //没读完指定长度,但缓冲区没数据时返回当前n
     34             InputStream input = in;
     35             if (input != null && input.available() <= 0)
     36                 return n;
     37         }
     38     }
     39 
     40 
     41     /**
     42      * read1方法是该read底层用来读取缓冲区buf的数据进指定数组的方法
     43      * 而fill方法又是read1方法中用来读取底层字节流到缓冲区buf的方法
     44      * 读取数据写进指定数组的一部分,必要时每次从底层流尽量读取数据
     45      */
     46     private int read1(byte[] b, int off, int len) throws IOException {
     47         int avail = count - pos; //开始时为0
     48         if (avail <= 0) {
     49             /* 如果所请求的长度大于等于缓冲区,并且还没读取过buf
    50         (即刚开始使用时,扩充缓冲区成本不值得,回归底层流),
    51 就没必要用缓冲区了,将直接从底层流读取数据。
    52 */ 53 if (len >= getBufIfOpen().length && markpos < 0) { 54 //直接调用底层流的read方法,写进指定的内存b 55 return getInIfOpen().read(b, off, len); 56 } 57 //请求fill()方法来读取底层流数据(多次使用后如果长度大于缓冲区,为了数据保护,将扩充缓冲区) 58 fill(); 59 avail = count - pos; //avail是 60 if (avail <= 0) return -1; 61 } 62 int cnt = (avail < len) ? avail : len; //cnt是要写入b的字节数,如果b中剩余字节数avail比要刷入的数据长度len大,则cnt为len 63 System.arraycopy(getBufIfOpen(), pos, b, off, cnt); //复制指定范围非空buf数据到b 64 pos += cnt; 65 return cnt; 66 } 67 68 69 //fill()方法填充空间,是底层用来读取流数据到缓冲区buf 70 /** 71 * Fills the buffer with more data, taking into account 72 * shuffling and other tricks for dealing with marks. 73 * Assumes that it is being called by a synchronized method. 74 * This method also assumes that all data has already been read in, 75 * hence pos > count. 76 */ 77 private void fill() throws IOException { 78 byte[] buffer = getBufIfOpen(); 79 //pos是起始/下一次读取buffer的位置,markpos是最新一次已读取的位置,count是缓冲数组被填充的大小-1(因为是作为index存在的,从0开始) 80 //起始小于零表明没有pos移动,从源码可知 81 if (markpos < 0) 82 pos = 0; /* no mark: throw away the buffer */ 83 //当pos比buffer更长时,即 84 else if (pos >= buffer.length) /* no room left in buffer */ 85 //markpos也有前移时,数组自我复制丢弃早期部分 86 if (markpos > 0) { /* can throw away early part of the buffer */ 87 int sz = pos - markpos; 88 System.arraycopy(buffer, markpos, buffer, 0, sz); 89 pos = sz; 90 markpos = 0; 91 //buffer大小超过理论规模时,重置,通过改变pos“丢弃”缓冲区内容 92 } else if (buffer.length >= marklimit) { 93 markpos = -1; /* buffer got too big, invalidate mark */ 94 pos = 0; /* drop buffer contents */ 95 //buffer大小超过本地VM内存限制:MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8 96 } else if (buffer.length >= MAX_BUFFER_SIZE) { 97 throw new OutOfMemoryError("Required array size too large"); 98 } else { /* grow buffer */ //没有顾忌时,扩充缓冲区大小 99 int nsz = (pos <= MAX_BUFFER_SIZE - pos) ? 100 pos * 2 : MAX_BUFFER_SIZE; 101 if (nsz > marklimit) 102 nsz = marklimit; 103 byte nbuf[] = new byte[nsz]; 104 System.arraycopy(buffer, 0, nbuf, 0, pos); 105 /*AtomicReferenceFieldUpdater是一个基于反射的工具类, 106 它能对指定类的指定的volatile引用字段进行原子更新。 107 (注意这个字段不能是private的) , 108 从源码知getBufIfOpen返回的是值传递的protected volatile byte buf[] 109 */ 110 if (!bufUpdater.compareAndSet(this, buffer, nbuf)) { 111 // Can't replace buf if there was an async close. 112 // Note: This would need to be changed if fill() 113 // is ever made accessible to multiple threads. 114 // But for now, the only way CAS can fail is via close. 115 // assert buf == null; 116 throw new IOException("Stream closed"); 117 } 118 buffer = nbuf; 119 } 120 //pos小于buf.length时,从底层流到缓冲区,使用InputStream的read(byte[])方法 121 count = pos; 122 int n = getInIfOpen().read(buffer, pos, buffer.length - pos); 123 if (n > 0) 124 count = n + pos; 125 } 126

    总结:通过以上源码我们可以看到:

      1)read(byte[])方法运行初始就用getBufIfOpen判断流关闭没有,因为缓冲流关闭后缓冲区失效,getBufIfOpen将抛出异常;

      2)read(byte[])方法中的read1方法是该read底层,用来读取缓冲区buf的数据进指定数组的方法,而fill方法又是read1方法中,用来读取底层字节流到缓冲区buf的方法,层层封装外包

      3)read(byte[]) <-- read1(byte[]) <-- fill() <-- getInIfOpen().read(buf) <-- InputStream 层层外包,

        这里getInIfOpen()返回一个非空底层流InputStream,并调用底层流的read(byte[])方法读取流数据到缓冲区buf,

        所以当我们只是关闭底层流这些嵌套流也跟着“关闭”,但是会留下缓冲数组buf,这有时可以利用,有时要注意关闭避免浪费资源;

         以下是close()的源码分析:

     1  1     public void close() throws IOException {
     2  2         byte[] buffer;
     3  3         while ( (buffer = buf) != null) {
     4  4             if (bufUpdater.compareAndSet(this, buffer, null)) { // 会将缓冲区buf的数据清空并释放缓冲区,也就是buf=null
     5  5                 InputStream input = in; //引用传递,input和in同指向节点流对象
     6  6                 in = null; //修改强引用,使底层流引用变量失效,即任何人都不能通过in去引用底层流了
     7  7                 if (input != null) //然后交给input单独来非空判断和执行关闭操作
     8  8                     input.close(); //调用节点流的close(),和native相关
     9  9                 return;
    10 10             }
    11 11             // Else retry in case a new buf was CASed in fill()
    12 12         }
    13 13     }
    View Code

      4)当BufferedInputStream缓冲区数据用完时,自动从底层输入流中补充数据(stream-->buf--read buf-->I)

      5)关于read(byte[])缓冲区buf空间大小限制性能的问题:

        (1)一开始使用缓冲流时,如果请求填充的长度len大于缓冲区大小buf.length,将直接使用底层流的read(byte[])方法,原因是扩充缓冲区的成本大于缓冲带来的便利;

        (2)多次使用缓冲流后,一样如果请求填充的长度len大于缓冲区大小buf.length,为了数据的完整安全,在内部的fill()方法中扩充缓冲区大小,而这要付出相应成本限制性能,所以缓冲区大小要谨慎设定。

      6)在缓冲区可用数据小于目标数组b的时候,使用System.arraycopy整体将缓冲区从pos位置起的数据覆盖到目标数组上    

    1       int cnt = (avail < len) ? avail : len; //cnt是要写入b的字节数,如果b中剩余字节数avail比要刷入的数据长度len大,则cnt为len
    2 
    3       System.arraycopy(getBufIfOpen(), pos, b, off, cnt); //复制指定范围非空buf数据到b

    BufferedOutputStream工作流程


    流程:I--write buf-->buf-->stream,我们通过两个write输出我们的数据,而数据暂时积聚在buf中,等待flush

    1.当一个BufferedOutputStream被创建时,一个内部的缓冲区 byte[] buf = new byte[size] 也被建立,size默认是8192也就是默认创建一个8kb大小的缓存空间,

     最终的数据去向由底层流决定,比如new FileOutputStream("a.txt")去向就是a.txt,而我们过滤流的数据来源是节点流!

    2.BufferedOutputStream在内部缓冲区存储程序的输出数据,这样就不会每次调用write方法时,就把数据写到底层的输出流;

    3.当BufferedOutputStream的内部缓冲区或者它被刷新(flush),数据一次性写到底层的输出流

      constructor源码分析:

     1     public BufferedOutputStream(OutputStream out) {
     2         this(out, 8192);
     3     }
     4 
     5     //这里与BufferedInputStream同理,不再赘述
     6     public BufferedOutputStream(OutputStream out, int size) {
     7         super(out);
     8         if (size <= 0) {
     9             throw new IllegalArgumentException("Buffer size <= 0");
    10         }
    11         buf = new byte[size];
    12     }

      write(int)源码分析:

     1     public synchronized void write(int b) throws IOException {
     2         if (count >= buf.length) { //当count++到buf.length的长度,表明缓冲区已满
     3             flushBuffer(); //刷出缓存到底层字节输出流
     4         }
     5         buf[count++] = (byte)b; //此时缓冲区本身未满或者flush后空了(count=0),先把b放在缓冲区buf中
     6     }
     7 
     8 
     9     /*刷出内部的缓存到底层字节输出流*/
    10     private void flushBuffer() throws IOException {
    11         if (count > 0) {
    12             out.write(buf, 0, count); //实质上利用底层流的write(byte[])
    13             count = 0; //全部刷出,count=0,作为标志位与buf[count++]联合来刷新
    14         }
    15     }

      write(byte[], int, int)源码分析:

     1      public synchronized void write(byte b[], int off, int len) throws IOException {
     2 
     3          /* 在指定数组数据到buf时,如果数据的长度比buf长,
     4             可能在传输过程中需要发出超长len,所以将buf中之前的工作数据刷出,
     5             然后直接调用底层流的write(byte[])方法输出,
     6             这个判断暗地里也限制了初始时就len过长的情况(count=0)
     7           */
     8          if (len >= buf.length) {
     9              flushBuffer();
    10              out.write(b, off, len);
    11              return;
    12          }
    13 
    14          /*表明缓冲区已满,刷出*/
    15          if (len > buf.length - count) {
    16              flushBuffer();
    17          }
    18 
    19          /*在经过上面的判断后,说明len<buf.length且count>0,
    20             已使用过buf,只是剩余空间不足以承载,刷出数据后,
    21             利用arraycopy将数据存入buf
    22           */
    23          System.arraycopy(b, off, buf, count, len);
    24          count += len; //count增加填充的字节数
    25      }    

      flush()源码分析:

     1     public synchronized void flush() throws IOException {
     2         /*刷出缓冲区的数据到基流*/
     3         flushBuffer();
     4 
     5         /* 调用基流的flush方法,这里考虑到了嵌套流,
     6            普通的节点流flush方法是空方法,
     7            如果嵌套的依旧是一个带缓存的流,那么可递归每一层的flush
     8            这迫使任何缓存输出的字节被写到底层流上         
     9          */
    10         out.flush();
    11     }    

    总结:通过以上源码我们可以看到:

      1)write(int)时,若buf已满,将自动刷出buf中的数据到流;

      2)刷出到流的内部方法flushBuffer利用的是基流的write(byte[], int, int)方法;

      3)没有close方法,只给关闭底层流,缓存输出流无需关闭;

      4)flush方法调用基流的flush方法,这里考虑到了嵌套流,因为普通的节点流flush方法是空方法!

        如果嵌套的依旧是一个带缓存的流那么可递归flush这迫使任何缓存输出的字节被写到底层流上

      5) write(byte[], int, int)时,

       (1)如果数据的长度比buf长,可能在传输过程中需要发出超长len,所以将buf中之前的工作数据刷出,然后直接调用底层流的write(byte[])方法自行输出,这个判断暗地里也限制了初始时就len过长的情况(count=0);

       (2)无需刷出缓存的情况下,使用arraycopy把要输出的byte[]数据,从count位置开始,拷贝到buf中。

    和节点流ByteArrayInput/OutputStream的区别


    1.ByteArrayInputStream是节点流;BufferedInputStream是过滤流;

    2.ByteArrayInputStream需要使用者提供一个缓冲数组,是自带缓冲功能的流,由构造器传入;BufferedInputStream默认自己创建一个缓冲数组,默认4096长度,即4kB大小;

    3.ByteArrayInputStream利用继承关系扩展流的功能;BufferedInputStream利用装饰模式扩展流的功能;

    4.类中方法的原理都差不多,具体参阅源码

      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 
     28 /**
     29  * A <code>ByteArrayInputStream</code> contains
     30  * an internal buffer that contains bytes that
     31  * may be read from the stream. An internal
     32  * counter keeps track of the next byte to
     33  * be supplied by the <code>read</code> method.
     34  * <p>
     35  * Closing a <tt>ByteArrayInputStream</tt> has no effect. The methods in
     36  * this class can be called after the stream has been closed without
     37  * generating an <tt>IOException</tt>.
     38  *
     39  * @author  Arthur van Hoff
     40  * @see     java.io.StringBufferInputStream
     41  * @since   JDK1.0
     42  */
     43 public
     44 class ByteArrayInputStream extends InputStream {
     45 
     46     /**
     47      * An array of bytes that was provided
     48      * by the creator of the stream. Elements <code>buf[0]</code>
     49      * through <code>buf[count-1]</code> are the
     50      * only bytes that can ever be read from the
     51      * stream;  element <code>buf[pos]</code> is
     52      * the next byte to be read.
     53      */
     54     protected byte buf[];
     55 
     56     /**
     57      * The index of the next character to read from the input stream buffer.
     58      * This value should always be nonnegative
     59      * and not larger than the value of <code>count</code>.
     60      * The next byte to be read from the input stream buffer
     61      * will be <code>buf[pos]</code>.
     62      */
     63     protected int pos;
     64 
     65     /**
     66      * The currently marked position in the stream.
     67      * ByteArrayInputStream objects are marked at position zero by
     68      * default when constructed.  They may be marked at another
     69      * position within the buffer by the <code>mark()</code> method.
     70      * The current buffer position is set to this point by the
     71      * <code>reset()</code> method.
     72      * <p>
     73      * If no mark has been set, then the value of mark is the offset
     74      * passed to the constructor (or 0 if the offset was not supplied).
     75      *
     76      * @since   JDK1.1
     77      */
     78     protected int mark = 0;
     79 
     80     /**
     81      * The index one greater than the last valid character in the input
     82      * stream buffer.
     83      * This value should always be nonnegative
     84      * and not larger than the length of <code>buf</code>.
     85      * It  is one greater than the position of
     86      * the last byte within <code>buf</code> that
     87      * can ever be read  from the input stream buffer.
     88      */
     89     protected int count;
     90 
     91     /**
     92      * Creates a <code>ByteArrayInputStream</code>
     93      * so that it  uses <code>buf</code> as its
     94      * buffer array.
     95      * The buffer array is not copied.
     96      * The initial value of <code>pos</code>
     97      * is <code>0</code> and the initial value
     98      * of  <code>count</code> is the length of
     99      * <code>buf</code>.
    100      *
    101      * @param   buf   the input buffer.
    102      */
    103     public ByteArrayInputStream(byte buf[]) {
    104         this.buf = buf;
    105         this.pos = 0;
    106         this.count = buf.length;
    107     }
    108 
    109     /**
    110      * Creates <code>ByteArrayInputStream</code>
    111      * that uses <code>buf</code> as its
    112      * buffer array. The initial value of <code>pos</code>
    113      * is <code>offset</code> and the initial value
    114      * of <code>count</code> is the minimum of <code>offset+length</code>
    115      * and <code>buf.length</code>.
    116      * The buffer array is not copied. The buffer's mark is
    117      * set to the specified offset.
    118      *
    119      * @param   buf      the input buffer.
    120      * @param   offset   the offset in the buffer of the first byte to read.
    121      * @param   length   the maximum number of bytes to read from the buffer.
    122      */
    123     public ByteArrayInputStream(byte buf[], int offset, int length) {
    124         this.buf = buf;
    125         this.pos = offset;
    126         this.count = Math.min(offset + length, buf.length);
    127         this.mark = offset;
    128     }
    129 
    130     /**
    131      * Reads the next byte of data from this input stream. The value
    132      * byte is returned as an <code>int</code> in the range
    133      * <code>0</code> to <code>255</code>. If no byte is available
    134      * because the end of the stream has been reached, the value
    135      * <code>-1</code> is returned.
    136      * <p>
    137      * This <code>read</code> method
    138      * cannot block.
    139      *
    140      * @return  the next byte of data, or <code>-1</code> if the end of the
    141      *          stream has been reached.
    142      */
    143     public synchronized int read() {
    144         return (pos < count) ? (buf[pos++] & 0xff) : -1;
    145     }
    146 
    147     /**
    148      * Reads up to <code>len</code> bytes of data into an array of bytes
    149      * from this input stream.
    150      * If <code>pos</code> equals <code>count</code>,
    151      * then <code>-1</code> is returned to indicate
    152      * end of file. Otherwise, the  number <code>k</code>
    153      * of bytes read is equal to the smaller of
    154      * <code>len</code> and <code>count-pos</code>.
    155      * If <code>k</code> is positive, then bytes
    156      * <code>buf[pos]</code> through <code>buf[pos+k-1]</code>
    157      * are copied into <code>b[off]</code>  through
    158      * <code>b[off+k-1]</code> in the manner performed
    159      * by <code>System.arraycopy</code>. The
    160      * value <code>k</code> is added into <code>pos</code>
    161      * and <code>k</code> is returned.
    162      * <p>
    163      * This <code>read</code> method cannot block.
    164      *
    165      * @param   b     the buffer into which the data is read.
    166      * @param   off   the start offset in the destination array <code>b</code>
    167      * @param   len   the maximum number of bytes read.
    168      * @return  the total number of bytes read into the buffer, or
    169      *          <code>-1</code> if there is no more data because the end of
    170      *          the stream has been reached.
    171      * @exception  NullPointerException If <code>b</code> is <code>null</code>.
    172      * @exception  IndexOutOfBoundsException If <code>off</code> is negative,
    173      * <code>len</code> is negative, or <code>len</code> is greater than
    174      * <code>b.length - off</code>
    175      */
    176     public synchronized int read(byte b[], int off, int len) {
    177         if (b == null) {
    178             throw new NullPointerException();
    179         } else if (off < 0 || len < 0 || len > b.length - off) {
    180             throw new IndexOutOfBoundsException();
    181         }
    182 
    183         if (pos >= count) {
    184             return -1;
    185         }
    186 
    187         int avail = count - pos;
    188         if (len > avail) {
    189             len = avail;
    190         }
    191         if (len <= 0) {
    192             return 0;
    193         }
    194         System.arraycopy(buf, pos, b, off, len);
    195         pos += len;
    196         return len;
    197     }
    198 
    199     /**
    200      * Skips <code>n</code> bytes of input from this input stream. Fewer
    201      * bytes might be skipped if the end of the input stream is reached.
    202      * The actual number <code>k</code>
    203      * of bytes to be skipped is equal to the smaller
    204      * of <code>n</code> and  <code>count-pos</code>.
    205      * The value <code>k</code> is added into <code>pos</code>
    206      * and <code>k</code> is returned.
    207      *
    208      * @param   n   the number of bytes to be skipped.
    209      * @return  the actual number of bytes skipped.
    210      */
    211     public synchronized long skip(long n) {
    212         long k = count - pos;
    213         if (n < k) {
    214             k = n < 0 ? 0 : n;
    215         }
    216 
    217         pos += k;
    218         return k;
    219     }
    220 
    221     /**
    222      * Returns the number of remaining bytes that can be read (or skipped over)
    223      * from this input stream.
    224      * <p>
    225      * The value returned is <code>count&nbsp;- pos</code>,
    226      * which is the number of bytes remaining to be read from the input buffer.
    227      *
    228      * @return  the number of remaining bytes that can be read (or skipped
    229      *          over) from this input stream without blocking.
    230      */
    231     public synchronized int available() {
    232         return count - pos;
    233     }
    234 
    235     /**
    236      * Tests if this <code>InputStream</code> supports mark/reset. The
    237      * <code>markSupported</code> method of <code>ByteArrayInputStream</code>
    238      * always returns <code>true</code>.
    239      *
    240      * @since   JDK1.1
    241      */
    242     public boolean markSupported() {
    243         return true;
    244     }
    245 
    246     /**
    247      * Set the current marked position in the stream.
    248      * ByteArrayInputStream objects are marked at position zero by
    249      * default when constructed.  They may be marked at another
    250      * position within the buffer by this method.
    251      * <p>
    252      * If no mark has been set, then the value of the mark is the
    253      * offset passed to the constructor (or 0 if the offset was not
    254      * supplied).
    255      *
    256      * <p> Note: The <code>readAheadLimit</code> for this class
    257      *  has no meaning.
    258      *
    259      * @since   JDK1.1
    260      */
    261     public void mark(int readAheadLimit) {
    262         mark = pos;
    263     }
    264 
    265     /**
    266      * Resets the buffer to the marked position.  The marked position
    267      * is 0 unless another position was marked or an offset was specified
    268      * in the constructor.
    269      */
    270     public synchronized void reset() {
    271         pos = mark;
    272     }
    273 
    274     /**
    275      * Closing a <tt>ByteArrayInputStream</tt> has no effect. The methods in
    276      * this class can be called after the stream has been closed without
    277      * generating an <tt>IOException</tt>.
    278      */
    279     public void close() throws IOException {
    280     }
    281 
    282 }
    ByteArrayInputStream
      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 
     28 import java.util.Arrays;
     29 
     30 /**
     31  * This class implements an output stream in which the data is
     32  * written into a byte array. The buffer automatically grows as data
     33  * is written to it.
     34  * The data can be retrieved using <code>toByteArray()</code> and
     35  * <code>toString()</code>.
     36  * <p>
     37  * Closing a <tt>ByteArrayOutputStream</tt> has no effect. The methods in
     38  * this class can be called after the stream has been closed without
     39  * generating an <tt>IOException</tt>.
     40  *
     41  * @author  Arthur van Hoff
     42  * @since   JDK1.0
     43  */
     44 
     45 public class ByteArrayOutputStream extends OutputStream {
     46 
     47     /**
     48      * The buffer where data is stored.
     49      */
     50     protected byte buf[];
     51 
     52     /**
     53      * The number of valid bytes in the buffer.
     54      */
     55     protected int count;
     56 
     57     /**
     58      * Creates a new byte array output stream. The buffer capacity is
     59      * initially 32 bytes, though its size increases if necessary.
     60      */
     61     public ByteArrayOutputStream() {
     62         this(32);
     63     }
     64 
     65     /**
     66      * Creates a new byte array output stream, with a buffer capacity of
     67      * the specified size, in bytes.
     68      *
     69      * @param   size   the initial size.
     70      * @exception  IllegalArgumentException if size is negative.
     71      */
     72     public ByteArrayOutputStream(int size) {
     73         if (size < 0) {
     74             throw new IllegalArgumentException("Negative initial size: "
     75                                                + size);
     76         }
     77         buf = new byte[size];
     78     }
     79 
     80     /**
     81      * Increases the capacity if necessary to ensure that it can hold
     82      * at least the number of elements specified by the minimum
     83      * capacity argument.
     84      *
     85      * @param minCapacity the desired minimum capacity
     86      * @throws OutOfMemoryError if {@code minCapacity < 0}.  This is
     87      * interpreted as a request for the unsatisfiably large capacity
     88      * {@code (long) Integer.MAX_VALUE + (minCapacity - Integer.MAX_VALUE)}.
     89      */
     90     private void ensureCapacity(int minCapacity) {
     91         // overflow-conscious code
     92         if (minCapacity - buf.length > 0)
     93             grow(minCapacity);
     94     }
     95 
     96     /**
     97      * The maximum size of array to allocate.
     98      * Some VMs reserve some header words in an array.
     99      * Attempts to allocate larger arrays may result in
    100      * OutOfMemoryError: Requested array size exceeds VM limit
    101      */
    102     private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    103 
    104     /**
    105      * Increases the capacity to ensure that it can hold at least the
    106      * number of elements specified by the minimum capacity argument.
    107      *
    108      * @param minCapacity the desired minimum capacity
    109      */
    110     private void grow(int minCapacity) {
    111         // overflow-conscious code
    112         int oldCapacity = buf.length;
    113         int newCapacity = oldCapacity << 1;
    114         if (newCapacity - minCapacity < 0)
    115             newCapacity = minCapacity;
    116         if (newCapacity - MAX_ARRAY_SIZE > 0)
    117             newCapacity = hugeCapacity(minCapacity);
    118         buf = Arrays.copyOf(buf, newCapacity);
    119     }
    120 
    121     private static int hugeCapacity(int minCapacity) {
    122         if (minCapacity < 0) // overflow
    123             throw new OutOfMemoryError();
    124         return (minCapacity > MAX_ARRAY_SIZE) ?
    125             Integer.MAX_VALUE :
    126             MAX_ARRAY_SIZE;
    127     }
    128 
    129     /**
    130      * Writes the specified byte to this byte array output stream.
    131      *
    132      * @param   b   the byte to be written.
    133      */
    134     public synchronized void write(int b) {
    135         ensureCapacity(count + 1);
    136         buf[count] = (byte) b;
    137         count += 1;
    138     }
    139 
    140     /**
    141      * Writes <code>len</code> bytes from the specified byte array
    142      * starting at offset <code>off</code> to this byte array output stream.
    143      *
    144      * @param   b     the data.
    145      * @param   off   the start offset in the data.
    146      * @param   len   the number of bytes to write.
    147      */
    148     public synchronized void write(byte b[], int off, int len) {
    149         if ((off < 0) || (off > b.length) || (len < 0) ||
    150             ((off + len) - b.length > 0)) {
    151             throw new IndexOutOfBoundsException();
    152         }
    153         ensureCapacity(count + len);
    154         System.arraycopy(b, off, buf, count, len);
    155         count += len;
    156     }
    157 
    158     /**
    159      * Writes the complete contents of this byte array output stream to
    160      * the specified output stream argument, as if by calling the output
    161      * stream's write method using <code>out.write(buf, 0, count)</code>.
    162      *
    163      * @param      out   the output stream to which to write the data.
    164      * @exception  IOException  if an I/O error occurs.
    165      */
    166     public synchronized void writeTo(OutputStream out) throws IOException {
    167         out.write(buf, 0, count);
    168     }
    169 
    170     /**
    171      * Resets the <code>count</code> field of this byte array output
    172      * stream to zero, so that all currently accumulated output in the
    173      * output stream is discarded. The output stream can be used again,
    174      * reusing the already allocated buffer space.
    175      *
    176      * @see     java.io.ByteArrayInputStream#count
    177      */
    178     public synchronized void reset() {
    179         count = 0;
    180     }
    181 
    182     /**
    183      * Creates a newly allocated byte array. Its size is the current
    184      * size of this output stream and the valid contents of the buffer
    185      * have been copied into it.
    186      *
    187      * @return  the current contents of this output stream, as a byte array.
    188      * @see     java.io.ByteArrayOutputStream#size()
    189      */
    190     public synchronized byte toByteArray()[] {
    191         return Arrays.copyOf(buf, count);
    192     }
    193 
    194     /**
    195      * Returns the current size of the buffer.
    196      *
    197      * @return  the value of the <code>count</code> field, which is the number
    198      *          of valid bytes in this output stream.
    199      * @see     java.io.ByteArrayOutputStream#count
    200      */
    201     public synchronized int size() {
    202         return count;
    203     }
    204 
    205     /**
    206      * Converts the buffer's contents into a string decoding bytes using the
    207      * platform's default character set. The length of the new <tt>String</tt>
    208      * is a function of the character set, and hence may not be equal to the
    209      * size of the buffer.
    210      *
    211      * <p> This method always replaces malformed-input and unmappable-character
    212      * sequences with the default replacement string for the platform's
    213      * default character set. The {@linkplain java.nio.charset.CharsetDecoder}
    214      * class should be used when more control over the decoding process is
    215      * required.
    216      *
    217      * @return String decoded from the buffer's contents.
    218      * @since  JDK1.1
    219      */
    220     public synchronized String toString() {
    221         return new String(buf, 0, count);
    222     }
    223 
    224     /**
    225      * Converts the buffer's contents into a string by decoding the bytes using
    226      * the named {@link java.nio.charset.Charset charset}. The length of the new
    227      * <tt>String</tt> is a function of the charset, and hence may not be equal
    228      * to the length of the byte array.
    229      *
    230      * <p> This method always replaces malformed-input and unmappable-character
    231      * sequences with this charset's default replacement string. The {@link
    232      * java.nio.charset.CharsetDecoder} class should be used when more control
    233      * over the decoding process is required.
    234      *
    235      * @param      charsetName  the name of a supported
    236      *             {@link java.nio.charset.Charset charset}
    237      * @return     String decoded from the buffer's contents.
    238      * @exception  UnsupportedEncodingException
    239      *             If the named charset is not supported
    240      * @since      JDK1.1
    241      */
    242     public synchronized String toString(String charsetName)
    243         throws UnsupportedEncodingException
    244     {
    245         return new String(buf, 0, count, charsetName);
    246     }
    247 
    248     /**
    249      * Creates a newly allocated string. Its size is the current size of
    250      * the output stream and the valid contents of the buffer have been
    251      * copied into it. Each character <i>c</i> in the resulting string is
    252      * constructed from the corresponding element <i>b</i> in the byte
    253      * array such that:
    254      * <blockquote><pre>
    255      *     c == (char)(((hibyte &amp; 0xff) &lt;&lt; 8) | (b &amp; 0xff))
    256      * </pre></blockquote>
    257      *
    258      * @deprecated This method does not properly convert bytes into characters.
    259      * As of JDK&nbsp;1.1, the preferred way to do this is via the
    260      * <code>toString(String enc)</code> method, which takes an encoding-name
    261      * argument, or the <code>toString()</code> method, which uses the
    262      * platform's default character encoding.
    263      *
    264      * @param      hibyte    the high byte of each resulting Unicode character.
    265      * @return     the current contents of the output stream, as a string.
    266      * @see        java.io.ByteArrayOutputStream#size()
    267      * @see        java.io.ByteArrayOutputStream#toString(String)
    268      * @see        java.io.ByteArrayOutputStream#toString()
    269      */
    270     @Deprecated
    271     public synchronized String toString(int hibyte) {
    272         return new String(buf, hibyte, 0, count);
    273     }
    274 
    275     /**
    276      * Closing a <tt>ByteArrayOutputStream</tt> has no effect. The methods in
    277      * this class can be called after the stream has been closed without
    278      * generating an <tt>IOException</tt>.
    279      */
    280     public void close() throws IOException {
    281     }
    282 
    283 }
    ByteArrayOutputStream
  • 相关阅读:
    线程同步锁的使用方式
    EventBus简单封装
    Dagger2不自动生成daggerXXXcomponent
    android mvp模式
    第八天
    单词统计续
    学习进度第十一周
    第七天
    第六天
    第五天
  • 原文地址:https://www.cnblogs.com/ixenos/p/5729841.html
Copyright © 2020-2023  润新知