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