1. 程式人生 > >Java IO系列4 位元組流之PushbackInputStream

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