Java IO系列4 字节流之PushbackInputStream

PushbackInputStream

原理是在内部保存一个字节缓冲区,如果unRead一个字节,就会向这个缓冲区倒着写入数据,下一次read的时候,就会把该缓冲区里的字节读取出来。
当缓冲区里没数据时,跟别的字节输入流一样
这里写图片描述

但是当有数据时
例如:我们现在读取1数据,这个时候unRead 4个字节,顺序是20、21、22、23
当我们再次read的时候顺序是23、22、21、20、2
这里写图片描述

public
class PushbackInputStream extends FilterInputStream {
    //回退缓冲区,默认1字节
    protected byte[] buf;
    //回退区中最前面一个数据的位置,回退是倒着来的buf[--pos]  = X
    protected int pos;

    private void ensureOpen() throws IOException {
        if (in == null)
            throw new IOException("Stream closed");
    }


    public PushbackInputStream(InputStream in, int size) {
        super(in);
        if (size <= 0) {
            throw new IllegalArgumentException("size <= 0");
        }
        this.buf = new byte[size];
        this.pos = size;
    }

    //默认1字节的回退区
    public PushbackInputStream(InputStream in) {
        this(in, 1);
    }

    //如果回退区中没有数据,跟平常的字节输入流没什么两样。
    //如果回退区中有数据,先把回退区的数据读出来
    public int read() throws IOException {
        ensureOpen();
        if (pos < buf.length) {
            return buf[pos++] & 0xff;
        }
        return super.read();
    }

    //最多读取len个字节数据到b[]字节数组里,起始位置off
    //返回最多读到的数据
    public int read(byte[] b, int off, int len) throws IOException {
        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;
        }

        //检查回退区是否还有字节数据
        int avail = buf.length - pos;
        if (avail > 0) {

            if (len < avail) {
                //如果回退区里的可用数据比需要的len还多
                //直接avail = len
                avail = len;
            }
            System.arraycopy(buf, pos, b, off, avail);
            pos += avail;
            off += avail;
            len -= avail;
        }
        //如果回退区里的可用数据比需要的len还少,例如回退区里有5个字节可用,现在len是20,
        //那么现在len == 15;就是说还要在数据流里最多再读取15个字节(注意“最多”)
        if (len > 0) {
            len = super.read(b, off, len);
            if (len == -1) {
                return avail == 0 ? -1 : avail;
            }
            return avail + len;
        }
        return avail;
    }

    //把数据推到回退区中,注意是倒着的
    public void unread(int b) throws IOException {
        ensureOpen();
        if (pos == 0) {
            throw new IOException("Push back buffer is full");
        }
        buf[--pos] = (byte)b;
    }

    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);
    }

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

    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;
    }

    //跳过最多n个字节,如果回退区中有数据,把回退区里的数据也算上
    public long skip(long n) throws IOException {
        ensureOpen();
        if (n <= 0) {
            return 0;
        }

        long pskip = buf.length - pos;
        if (pskip > 0) {
            if (n < pskip) {
                pskip = n;
            }
            pos += pskip;
            n -= pskip;
        }
        if (n > 0) {
            pskip += super.skip(n);
        }
        return pskip;
    }

    public boolean markSupported() {
        return false;
    }

    public synchronized void mark(int readlimit) {
    }

   //不许重置,流里的数据一旦读取后,指针再也回不去了
    public synchronized void reset() throws IOException {
        throw new IOException("mark/reset not supported");
    }

    public synchronized void close() throws IOException {
        if (in == null)
            return;
        in.close();
        in = null;
        buf = null;
    }
}
        String data = "PushbackInputStream";
        ByteArrayInputStream in = new ByteArrayInputStream(data.getBytes());
        PushbackInputStream inputStream =  new PushbackInputStream(in, 4);
        int d;
        int count = 0;
        try {
            while ((d = inputStream.read())!=-1) {
                count++;
                if(count == 5){
                    inputStream.unread("push".getBytes());
                }
                System.out.print((char)d);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

输出结果:PushbpushackInputStream

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值