• PushBackInputStream


    PushBackInputStream 相较于其他的inputstream,新增了部分功能,即 push back 和unread.
    对于流中不需要的数据,PushBackInputStream 可以将数据重新推回流中。

    简单对源码进行下分析:
    android11的为例:
    PushbackInputStream继承自FilterInputStream。

    public class PushbackInputStream extends FilterInputStream 
    
    • 1

    内部定义了一个byte数组,就是push back 的缓冲池,大小可通过参数构建,默认为1.

     /**
         * The pushback buffer.
         * @since   JDK1.1
         */
        protected byte[] buf;
    
    • 1
    • 2
    • 3
    • 4
    • 5

    pos 代表 缓存数组中下一个要读取的字节数据的位置,这里要注意一点,可以根据构造方法中pos=size的赋值来看,该下标是从大到小执行的。

    protected int pos;
    
    • 1

    校验inputStream的合法性。

      private void ensureOpen() throws IOException {
            if (in == null)
                throw new IOException("Stream closed");
        }
    
    • 1
    • 2
    • 3
    • 4

    in 是父类 FilterInputStream中定义的参数:

     /**
         * The input stream to be filtered.
         */
        protected volatile InputStream in;
    
    • 1
    • 2
    • 3
    • 4

    接着我们看下构造函数:
    可以指定buf的大小,或者使用默认值1. 由于最小1,所以size<=0会抛出异常。

      public PushbackInputStream(InputStream in, int size) {
            super(in);
            if (size <= 0) {
                throw new IllegalArgumentException("size <= 0");
            }
            this.buf = new byte[size];
            this.pos = size;
        }
    
      public PushbackInputStream(InputStream in) {
            this(in, 1);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    read方法一次读取一个字节;首先校验in的合法性,然后优先读取缓存中的数据,否则就直接调用in的read方法。

     public int read() throws IOException {
            ensureOpen();
            if (pos < buf.length) {
                return buf[pos++] & 0xff;
            }
            return super.read();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    还可以读取多个字节。
    param1:承载读取数据的byte数组,
    param2:从数组的哪个pos开始,
    param3:存储的长度。

        public int read(byte[] b, int off, int len) throws IOException {
            //校验in的合法性
            ensureOpen();
            //校验参数的合法性
            if (b == null) {
                throw new NullPointerException();
            } else if (off < 0 || len < 0 || len > b.length - off) {
                throw new IndexOutOfBoundsException();
            } else if (len == 0) {
                return 0;
            }
           //push back buffer的实际存储数量,这里大于0说明buf中有存储数据,因为buf是从buf.length开始的。缓存区满了的话,pos=0
            int avail = buf.length - pos;
            
            if (avail > 0) {
               //需要读取的数值小于缓存buf中的数据量
                if (len < avail) {
                    avail = len;
                }
                //指定数据长度拷贝到传入的byte数组中。
                System.arraycopy(buf, pos, b, off, avail);
                pos += avail;
                off += avail;
                len -= avail;
            }
            //buf无数据,直接调用read读取。
            if (len > 0) {
                len = super.read(b, off, len);
                if (len == -1) {
                    return avail == 0 ? -1 : avail;
                }
                return avail + len;
            }
            return avail;
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    一次回推一个字节,当pos == 0时,说明缓存区满了 ;否则就在–pos(前一个)写入数据。

     public void unread(int b) throws IOException {
            ensureOpen();
            if (pos == 0) {
                throw new IOException("Push back buffer is full");
            }
            //放入缓存区
            buf[--pos] = (byte)b;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    当然还可以一次回推多个字节,指定回推数组,从off开始len个字节。
    如果len>pos说明buf空间不足,同样会抛出异常。
    否则的话,pos 需要前移len.利用copy,写入数据。

    public void unread(byte[] b, int off, int len) throws IOException {
            ensureOpen();
            if (len > pos) {
                throw new IOException("Push back buffer is full");
            }
            pos -= len;
            System.arraycopy(b, off, buf, pos, len);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    不指定off,默认从0开始。

      public void unread(byte[] b) throws IOException {
           unread(b, 0, b.length);
       }
    
    • 1
    • 2
    • 3

    返回当前流可读取的数值。根据buf中已经存储的数值,返回interger的最大值或者父类in的available+buf中已经存储的数值.

     public int available() throws IOException {
            ensureOpen();
            int n = buf.length - pos;
            int avail = super.available();
            return n > (Integer.MAX_VALUE - avail)
                        ? Integer.MAX_VALUE
                        : n + avail;
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    另外就是PushBackInputStream不支持:

     public boolean markSupported() {
            return false;
        }
      public synchronized void mark(int readlimit) {
        }
    
    public synchronized void reset() throws IOException {
            throw new IOException("mark/reset not supported");
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
  • 相关阅读:
    数控车床中滚珠螺母的维护保养方法
    springboot + layui + pageHepler 实现table 表格分页并且多行小计功能
    基于NCF的多模块协同实例
    手机,蓝牙开发板,TTL/USB模块,电脑四者之间的通讯
    样式和格式代码
    C++ 迭代器 iterator 详解
    linux命令ar使用说明
    Vue实现Hello World
    Sermant运行流程学习笔记,速来抄作业
    QSS样式表的使用
  • 原文地址:https://blog.csdn.net/qq_23025319/article/details/126892585