ByteArrayInputStream是字节数组输入流,在内存中创建了一个字节数组,将输入流中读取的数据保存到字节数组的缓存区中.也就是说字节数组输入流将读取数据放到字节数组缓冲区中.
1.ByteArrayInputStream构造方法有两个:
public ByteArrayInputStream(byte buf[]) {}
public ByteArrayInputStream(byte buf[], int offset, int length) {}
2.内部变量
protected byte buf[];
protected int pos;
protected int mark = 0;
protected int count;
3.内部方法
public synchronized int read()
public synchronized int read(byte b[], int off, int len) {}
public synchronized long skip(long n) {}
public synchronized int available() {}
public boolean markSupported() {}
public void mark(int readAheadLimit) {}
public synchronized void reset() {}
public void close() throws IOException{}
public class ByteArrayInputStreamDemo {
public static void main(String[] args) {
byte[] bytes = "abcdefghijklmnopqrst".getBytes();
ByteArrayInputStream byteStream = new ByteArrayInputStream(bytes);
//avaiable表示剩余可字节数,除了a,还剩19个字节
if(byteStream.available()>0) {
System.out.println((char)byteStream.read()+"------剩余可读字节数="+byteStream.available());
}
for(int i = 0 ; i < 3;i++) {
if(byteStream.available()>0) {
System.out.println((char)byteStream.read());
}
}
//现在位置是d,跳过3个字节,下一个字节是h
long skip = byteStream.skip(3);
System.out.println((char)byteStream.read()+"-----跳过字节数="+skip);
if(byteStream.markSupported()) {
System.out.println("support mark");
}
//现在是位置在i,进行标记.
byteStream.mark(0);
//使用字节数组,一次性读取三个字节.
byte[] byteArray = new byte[3];
byteStream.read(byteArray, 0, 2);
System.out.println(new String(byteArray));
//通过reset()方法将指针指到到mark位置
byteStream.reset();
System.out.println((char)byteStream.read());
}
运行结果:
a------剩余可读字节数=19
b
c
d
h-----跳过字节数=3
support mark
ij
代码分析:
(a)read()方法只能读取一个字节,读取的是下一个字节.
(b)read(buf,offset,len)方法,创建一个字节数组buf,将流里面数据读取到buf里面,位置从offset开始,长度是len.
(c)available()表示的是剩余可读的字节数,代码中当读取了a的时候,剩余的可读取的字节数量还剩19个字节.
(d)mark()将下一个的字节的位置进行标记,在读取到后面的几个字节后,可以使用reset()重新回到该位置.
(e)skip(n):表示跳过的字节数,下一个字节算起,代码中是e开始算起,跳过3个字节,到g结束.下一个读取的字节是h.
public class ByteArrayInputStream extends InputStream {
// 字节数组用于保存流里面的数据
protected byte buf[];
// 下一个会被读取的字节的索引
protected int pos;
// 标记的索引
protected int mark = 0;
// 流数据长度
protected int count;
// 构造函数--创建一个数据为buf字节数组的输入流
public ByteArrayInputStream(byte buf[]) {
this.buf = buf;
// 初始下一个读取的字节的索引是0
this.pos = 0;
// 当使用此构造方法时,count的大小值是buf.length
this.count = buf.length;
}
// 构造函数--创建字节输入流,它的数据是buf字节数组中,从offset索引开始,读取的长度为length的数据.
public ByteArrayInputStream(byte buf[], int offset, int length) {
this.buf = buf;
this.pos = offset;
// 当使用此构造方式时,count的大小是offset+length,buf.length中较小的值
this.count = Math.min(offset + length, buf.length);
// 当使用此构造方法时,标记位置的默认位置是offset
this.mark = offset;
}
// 读取下一个字节
public synchronized int read() {
return (pos < count) ? (buf[pos++] & 0xff) : -1;
}
// 将数据的读取到字节数组b中,off是将流数据写到数组开始的索引,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();
}
// 下一个读取字节的索引大于等于count,表示数据已经读完
if (pos >= count) {
return -1;
}
// len大于剩余可读的字节长度,len将会置为剩余可读字节长度
int avail = count - pos;
if (len > avail) {
len = avail;
}
if (len <= 0) {
return 0;
}
System.arraycopy(buf, pos, b, off, len);
pos += len;
return len;
}
// 跳过字节数,返回值是实际跳过的字节数量.
public synchronized long skip(long n) {
// 流数据长度count-下一个读取字节索引pos
long k = count - pos;
// 跳过字节数小于剩余可读字节数k时,跳过字节数为0,实际跳过字节数为0,是否实际是n
if (n < k) {
k = n < 0 ? 0 : n;
}
// 将pos加上实际跳过字节数.
pos += k;
return k;
}
// 可读字节数量,流数据长度count-下一个读取字节索引pos
public synchronized int available() {
return count - pos;
}
// 是否支持标记,此方法将返回的true
public boolean markSupported() {
return true;
}
// 标记当前位置。readAheadLimit在此无实际意义
public void mark(int readAheadLimit) {
mark = pos;
}
// 将位置重置到mark()方法标记的位置
public synchronized void reset() {
pos = mark;
}
// 此方法在流已经关闭的情况下,不会抛出异常
public void close() throws IOException {}
}
源码总结:
(a)count实际上流内容即字节数组可用的索引值+1,读取时将下一个要读取索引pos与count比较,小于count时,表明流字节数据里面存在这个索引,所以可以读取到流内容.
(b)流里面数据或者内容是要看构造函数里面buf字节数组,以及offset和读取长度len,下面的read(byte[] b, int off,int len)表示的 是将流里面内容读取到字节数组中,两者要注意区分.