ByteArrayInputStream 继承自 InputStream 父类。
字节数组输入流在内存中创建一个字节数组缓冲区,从输入流读取的数据保存在该字节数组缓冲区中。
属性
// 由该流的创建者提供的字节数组
protected byte buf[];
// pos可以理解为游标,指向数组中的哪个位置
protected int pos;
// 流中当前的标记位置,初始为0
protected int mark = 0;
// buf字节数组中比最后一位存放字节位置索引大1的位置
protected int count;
构造函数
// 根据给定的字节数组构造一个输入流
public ByteArrayInputStream(byte buf[]) {
this.buf = buf;
// 偏移量为0
this.pos = 0;
// count为字节数组的长度
this.count = buf.length;
}
// 根据给定的字节数组,偏移量,字节总数构造一个输入流
public ByteArrayInputStream(byte buf[], int offset, int length) {
this.buf = buf;
// 游标从offset位置开始
this.pos = offset;
// count最大也不能超出字节数组的总长度
this.count = Math.min(offset + length, buf.length);
// 标记位置也是从offset位置开始
this.mark = offset;
}
重要方法
read()
同步方法,读取字节数组buf中的下一个字节。返回值int,其实是返回的字节byte,转为int返回。
public synchronized int read() {
// 这里只要当前游标位置没有走完最后一个字节,即pos<count
// 就返回pos++位置的字节,转为int返回
// 如果游标已经走到了count位置,此位置已经没有字节可读,返回-1
return (pos < count) ? (buf[pos++] & 0xff) : -1;
}
read(byte b[], int off, int len)
也是同步方法,读取字节数组 buf 中一定数量的字节到字节数组 b 中,并从 b 数组 off 下标开始存放。
b 是目标数组,off 是目标数组 b 中开始存放的偏移量,len 为字节的数量。
返回值为读取的字节的总数量。
public synchronized int read(byte b[], int off, int len) {
// 目标数组不能为空,否则报空指针错误
if (b == null) {
throw new NullPointerException();
// 下标和长度应该合适,否则报范围异常
} else if (off < 0 || len < 0 || len > b.length - off) {
throw new IndexOutOfBoundsException();
}
// 如果游标pos走到了count位置,已经没有字节可读,返回-1
if (pos >= count) {
return -1;
}
// 剩余可读的字节数量avail,等于count减去当前读取位置
// pos位置的当前还未读取,一直到最后一个有字节的下标 (count-1) 总共的个数为
// (count-1)-pos+1 = count-pos
int avail = count - pos;
// 需要读取的字节数不能超过可读字节数
if (len > avail) {
len = avail;
}
// 需要读取的字节数如果不大于0,即不需要读取,那么直接返回读取的字节总数为0即可。
if (len <= 0) {
return 0;
}
// 执行数组拷贝,从buf的pos位置开始拷贝len个字节到b数组的off位置开始。
System.arraycopy(buf, pos, b, off, len);
// 数组复制完成后,游标pos要往后走len个长度
pos += len;
// 返回读取的字节总数len
return len;
}
skip(long n)
跳过字节数组buf中的 n 个字节。返回值为跳过的数量。
public synchronized long skip(long n) {
// k为当前可读的字节数量
long k = count - pos;
// 如果需跳过的比剩余的可读字节少
if (n < k) {
// 那么需跳过多少字节就可以跳过多少
k = n < 0 ? 0 : n;
}
// 上边如果n>k,即需跳过的字节比剩余字节还多,那么就全跳过即可
// 这里游标要向后移动k个位置,因为跳过了k个字节
pos += k;
// 返回跳过的字节总数k
return k;
}
available()
返回字节数组中可以读取的剩余字节总数。
(count-1) 位置是最后一个有字节的位置,
pos 位置是当前游标的位置(还未读取),
那么总数为 (count-1)-pos+1 = count-pos 。
public synchronized int available() {
return count - pos;
}
mark/reset
// 支持标记及重置位置
public boolean markSupported() {
return true;
}
// 将当前游标位置设置为标记点,此标记点可用于还原重置
// 注意readAheadLimit无意义
public void mark(int readAheadLimit) {
mark = pos;
}
// 还原位置,将之前保存的标记为作为游标位置
public synchronized void reset() {
pos = mark;
}