Java 学习笔记 - IO篇:可推回流 PushbackInputStream

Posted 笑虾

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 学习笔记 - IO篇:可推回流 PushbackInputStream相关的知识,希望对你有一定的参考价值。

Java 学习笔记 - IO篇:可推回流 PushbackInputStream

简介

  1. 封装一个 InputStream 并为其提供一个缓冲区
    1.1. 缓冲区大小默认 1 byte
    1.2. 构造函数中可以设置缓冲区大小:PushbackInputStream(InputStream in, int size)
  2. read 读取,unread 推回
  3. 如果执行了 unread 则会把数据填进缓冲区
    3.1. 下次读取先从缓冲区取。
    3.2. 不足的再到底层流中去取。

虽然叫推回但并没有限制readunread。所以下面我先把缓冲区填满,再读。

测试代码

@Test
public void pushbackInputStreamTest() throws IOException 
    byte[] 笨笨 = 1,2,3,4,5,6,7,8,9,10;
    ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
    PushbackInputStream pbis = new PushbackInputStream(bais, 10);
    pbis.unread(笨笨, 0, 3);
    pbis.unread(笨笨, 6, 3);
    
    byte[] 笑虾1 = new byte[10];
    int l1 = pbis.read(笑虾1, 0, 5);
    byte[] 笑虾2 = new byte[10];
    int l2 = pbis.read(笑虾2, 0, 8);
    byte[] 笑虾3 = new byte[10];
    int l3 = pbis.read(笑虾3, 0, 9);
    
    System.out.println("读取了: "+l1); // 读取了: 5
    System.out.println("读取了: "+l2); // 读取了: 8
    System.out.println("读取了: "+l3); // 读取了: 3

unread

unread 示意图

  1. 缓冲区为时,pos 等于 buf.length;缓冲区已时,pos 等于 0
  2. 每次 unreadpos向左移,永远指向有数据区的开始索引。(因为read时就pos这里开始读)
  3. 多次 unread 的数据是整块整块放进来的。第一次1,2,3,第二次7,8,9

unread 源码

public void unread(byte[] b, int off, int len) throws IOException 
    //  检查:输入流如果为 null 抛异常 IOException("Stream closed");
    ensureOpen();
    // 要推进来的数据,超过缓冲区大小
    if (len > pos) 
        throw new IOException("Push back buffer is full");
    
    // 算出还剩余多少可推回空间
    pos -= len;
    // 把数据拷进缓冲区
    System.arraycopy(b, off, buf, pos, len);

read

read 示意图

  1. 先取缓冲区。
  2. 再取底层流。

read 源码

public int read(byte[] b, int off, int len) throws IOException 
    /**
     *  1. 检查:输入流如果为 null 抛异常 IOException("Stream closed");
     *  2. 检测:数组 b 不能为 null
     *  3. 检查:是否偏移量、长度 < 0,是否要读取的【长度】超过数组【可用空间】。
     *  4. 如果长度为 0 直接返 0
     */
    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;
    
    /**
     * 1. 缓冲区中可用数据长度 = 缓冲区长度 - 剩余缓冲空间
     *      pos: 推回缓冲区中的位置,将读取该位置的下一个字节。
     *      缓冲区为空时,pos 等于 buf.length;缓冲区已满时,pos 等于 0。
     * 2. 缓冲中有可用数据,先从缓冲区取。
     *      取完更新 pos 位置;
     *      偏移已取的数量,为下次读取作准备;
     *      减掉已经取得数量,算出还需要取多少长度。
     */
    int avail = buf.length - pos;
    if (avail > 0) 
        if (len < avail) 
            avail = len;
        
        System.arraycopy(buf, pos, b, off, avail);
        pos += avail;
        off += avail;
        len -= avail;
    
    /**
     * 如果 len 大于 0 表示缓冲区的数据取完了,还差 len 个长度。
     * 1. 从底层流继续取。
     * 2. 如果底层流没数据返回 -1。算一下缓存区是不是有取到内容。如果有,返回其长度。
     * 3. 如果 缓存区、底层流 都成功取过数据,则返回总长度。
     */
    if (len > 0) 
        len = super.read(b, off, len);
        if (len == -1) 
            return avail == 0 ? -1 : avail;
        
        return avail + len;
    
    return avail;

参考资料

笑虾 :Java 学习笔记 - IO篇:常见的【IO流Stream】以及相互关系

PushbackInputStream

以上是关于Java 学习笔记 - IO篇:可推回流 PushbackInputStream的主要内容,如果未能解决你的问题,请参考以下文章

Java 学习笔记 - IO篇:对象流 ObjectInputStreamObjectOutputStream

Java 学习笔记 - IO篇:常见的IO流Stream以及相互关系

Java 学习笔记 - IO篇:读写文本文件txt

Java 学习笔记 - IO篇:文件与目录

Java 学习笔记 - IO篇:文件与目录

Java 学习笔记 - IO篇:常见的流Stream通道Channl以及相互关系