PushBackInputStream

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

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

public class PushbackInputStream extends FilterInputStream 

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

 /**
     * The pushback buffer.
     * @since   JDK1.1
     */
    protected byte[] buf;

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

protected int pos;

校验inputStream的合法性。

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

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

 /**
     * The input stream to be filtered.
     */
    protected volatile InputStream in;

接着我们看下构造函数:
可以指定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);
    }

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

 public int read() throws IOException {
        ensureOpen();
        if (pos < buf.length) {
            return buf[pos++] & 0xff;
        }
        return super.read();
    }

还可以读取多个字节。
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;
    }

一次回推一个字节,当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;
    }

当然还可以一次回推多个字节,指定回推数组,从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);
    }

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

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

返回当前流可读取的数值。根据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;
    }

另外就是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");
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`PushbackInputStream` 是Java IO库中的一个类,它提供了一种在读取输入流时将数据“推回”流中的方法,从而可以重新读取该数据。具体来说,`PushbackInputStream` 允许您在读取输入流时将最近读取的字节推回到流中,以便稍后再次读取它们。 例如,如果您正在读取一个文本文件,并且意外地读取了一些不是文本的字节,您可以使用 `PushbackInputStream` 将这些字节推回到流中,然后重新读取它们。 以下是一个示例代码片段,演示如何使用 `PushbackInputStream`: ```java import java.io.*; public class PushbackInputStreamExample { public static void main(String[] args) throws IOException { String str = "Hello, world!"; ByteArrayInputStream bais = new ByteArrayInputStream(str.getBytes()); PushbackInputStream pbis = new PushbackInputStream(bais); int b = pbis.read(); System.out.println((char) b); // Output: H pbis.unread(b); // push back the first byte read b = pbis.read(); // read the first byte again System.out.println((char) b); // Output: H byte[] buf = new byte[5]; pbis.read(buf); System.out.println(new String(buf)); // Output: "ello," pbis.unread(buf); // push back the five bytes read byte[] buf2 = new byte[5]; pbis.read(buf2); System.out.println(new String(buf2)); // Output: "ello," } } ``` 在这个示例中,我们首先将字符串 "Hello, world!" 转换为一个字节数组,然后使用 `ByteArrayInputStream` 将其包装为一个输入流。接下来,我们使用 `PushbackInputStream` 包装这个输入流。 我们首先读取第一个字节并将其输出。然后,我们使用 `unread` 方法将该字节推回流中,并再次读取它。然后,我们读取五个字节,并使用 `unread` 方法将它们推回流中。最后,我们再次读取五个字节,这次从流中读取了之前推回的字节。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值