BufferedInputStream
BufferedInputStream 是一个包装类,通过持有inputstream的引用,并在原有read方法基础上添加buffer数组缓存,实现了缓冲的目的。
构造函数,需要传入实际的inputstream,默认缓冲数组大小8192,8kb
public BufferedInputStream(InputStream in) {
this(in, DEFAULT_BUFFER_SIZE);
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`
当前缓冲区中数据长度
protected int count;
下一次读取位置的下标
protected int pos;
调用mark方法后,记录当前pos的位置
protected int markpos = -1;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
read方法,一次读取一个字节,内部有缓冲
public synchronized int read() throws IOException {
//如果下一次读取的位置,超出了缓冲区中的数据
if (pos >= count) {
//读取数据到buffer数组
fill();
if (pos >= count)
return -1;
}
return getBufIfOpen()[pos++] & 0xff;
}
向缓冲区中写数据
private void fill() throws IOException {
//获取当前缓冲数组
byte[] buffer = getBufIfOpen();
//如果未执行mark,pos重置为0
if (markpos < 0)
pos = 0;
//如果缓冲区满了
else if (pos >= buffer.length)
if (markpos > 0)
//计算markops 及之后的数据长度
int sz = pos - markpos;
//缓冲区数据从markops开始,拷贝sz长度的数据,到下标为0开始的地方
System.arraycopy(buffer, markpos, buffer, 0, sz);
//记录下一次读取位置
pos = sz;
markpos = 0;
}
//重置pos,markpos
else if (buffer.length >= marklimit) {
markpos = -1; /* buffer got too big, invalidate mark */
pos = 0; /* drop buffer contents */
}
else if (buffer.length >= MAX_BUFFER_SIZE) {
throw new OutOfMemoryError("Required array size too large");
}
else {
//如果pos<=最大缓冲/2,nsz为pos的2倍,否则nsz为最大缓冲区长度
int nsz = (pos <= MAX_BUFFER_SIZE - pos) ?
pos * 2 : MAX_BUFFER_SIZE;
//如果nsz超过标记的limit,扩容为marklimit
if (nsz > marklimit)
nsz = marklimit;
byte[] nbuf = new byte[nsz];
//旧数组数据考到新数组中
System.arraycopy(buffer, 0, nbuf, 0, pos);
if (!U.compareAndSetObject(this, BUF_OFFSET, buffer, nbuf)) {
// Can't replace buf if there was an async close.
// Note: This would need to be changed if fill()
// is ever made accessible to multiple threads.
// But for now, the only way CAS can fail is via close.
// assert buf == null;
throw new IOException("Stream closed");
}
buffer = nbuf;
}
count = pos;
int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
if (n > 0)
count = n + pos;
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
read 方法,读取数据到b数组,从off开始,读len个长度
public synchronized int read(byte b[], int off, int len)
throws IOException
{
getBufIfOpen(); // Check for closed stream
if ((off | len | (off + len) | (b.length - (off + len))) < 0) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return 0;
}
//累计已读取的数据长度
int n = 0;
//数据可能分多次读完。
for (;;) {
//计算返回的数据长度
int nread = read1(b, off + n, len - n);
//没数据了,返回
if (nread <= 0)
return (n == 0) ? nread : n;
n += nread;
//累计的数据>=len,b已经读满了,返回
if (n >= len)
return n;
// 流中数据已经读完了,返回
InputStream input = in;
if (input != null && input.available() <= 0)
return n;
}
}
private int read1(byte[] b, int off, int len) throws IOException {
//计算缓冲区中可用数据
int avail = count - pos;
//avail<=0,说明缓冲区已经读完了,如果缓冲区还有数据,会先返回缓冲区中数据,
if (avail <= 0) {
//len>=缓冲区长度 并且 markops <0,直接在流中读取,不再缓存
if (len >= getBufIfOpen().length && markpos < 0) {
return getInIfOpen().read(b, off, len);
}
//读取流数据,写入缓冲区
fill();
//重新计算缓冲区中可用数据
avail = count - pos;
if (avail <= 0) return -1;
}
//与len进行对比,算出需要读取的数据长度
int cnt = (avail < len) ? avail : len;
//拷贝数据
System.arraycopy(getBufIfOpen(), pos, b, off, cnt);
//pos 移到下一次需要读取的位置
pos += cnt;
return cnt;
}
BufferedOutputStream
BufferedOutputStream是一个带有缓冲功能的输出流,通过内部具体的outputstream实现读写,
缓冲区
protected byte buf[];
缓冲区中有效数据长度
protected int count;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
构造函数,默认缓冲区8M
public BufferedOutputStream(OutputStream out) {
this(out, 8192);
}
public BufferedOutputStream(OutputStream out, int size) {
super(out);
if (size <= 0) {
throw new IllegalArgumentException("Buffer size <= 0");
}
buf = new byte[size];
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public synchronized void write(int b) throws IOException {
//缓冲区满了,进行实际写入操作
if (count >= buf.length) {
flushBuffer();
}
将数据写入缓冲区
buf[count++] = (byte)b;
}
private void flushBuffer() throws IOException {
if (count > 0) {
//将缓冲区中数据写入,将count置位0,逻辑清空缓冲区
out.write(buf, 0, count);
count = 0;
}
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public synchronized void flush() throws IOException {
清空缓冲区,写入数据
flushBuffer();
// outputstream中 flush 方法是空实现,不进行任何操作
out.flush();
}