本文记录BufferedInputStream,BufferedOutputStream两个带缓冲的输入输出流。
BufferedInputStream继承于FilterInputStream,BufferedOutputStream继承于FilterOutputStream,这两个类为具体的装饰类,而FilterInputStream与FilterOutputStream为抽象装饰者类,但是该两个类不是抽象类。
BufferedInputStream
下面是BufferedInputStream的源码:
public class BufferedInputStream extends FilterInputStream {
//默认缓冲区大小
private static int DEFAULT_BUFFER_SIZE = 8192;
//最大缓冲区大小
private static int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
//内部缓冲数组
protected volatile byte buf[];
//为buf缓冲区提供原子的更新器
private static final
AtomicReferenceFieldUpdater<BufferedInputStream, byte[]> bufUpdater =
AtomicReferenceFieldUpdater.newUpdater
(BufferedInputStream.class, byte[].class, "buf");
//该值表示缓冲区下一个接收Input Stream字节的位置
protected int count;
//缓冲区的当前位置,也就是下一个从缓冲区读数据的位置,该值小于等于count
protected int pos;
//Mark标记的位置
protected int markpos = -1;
//pos - markpos > marklimit 时,Mark标记清除
protected int marklimit;
//获取该对象相应的InputStream对象
private InputStream getInIfOpen() throws IOException {
InputStream input = in;
if (input == null)
throw new IOException("Stream closed");
return input;
}
//获取buf缓冲区
private byte[] getBufIfOpen() throws IOException {
byte[] buffer = buf;
if (buffer == null)
throw new IOException("Stream closed");
return buffer;
}
//构造方法,调用父类方法,用于对InputStream 对象进行增强
public BufferedInputStream(InputStream in) {
this(in, DEFAULT_BUFFER_SIZE);
}
public BufferedInputStream(InputStream in, int size) {
super(in);
if (size <= 0) {
throw new IllegalArgumentException("Buffer size <= 0");
}
buf = new byte[size];
}
//读入字节填充缓冲区
private void fill() throws IOException {
byte[] buffer = getBufIfOpen();
//如果标记位无效,则直接填充缓冲区,并且覆盖原来的字节
if (markpos < 0)
pos = 0; /* no mark: throw away the buffer */
else if (pos >= buffer.length) /* no room left in buffer */
if (markpos > 0) { /* can throw away early part of the buffer */
int sz = pos - markpos;
System.arraycopy(buffer, markpos, buffer, 0, sz);
pos = sz;
markpos = 0;
} 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 { /* grow buffer */
int nsz = (pos <= MAX_BUFFER_SIZE - pos) ?
pos * 2 : MAX_BUFFER_SIZE;
if (nsz > marklimit)
nsz = marklimit;
byte nbuf[] = new byte[nsz];
System.arraycopy(buffer, 0, nbuf, 0, pos);
if (!bufUpdater.compareAndSet(this, 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;
}
//向缓冲区读取一个数据,若缓冲区没有数据,则使用fill方法填充缓冲区
public synchronized int read() throws IOException {
if (pos >= count) {
fill();
if (pos >= count)
return -1;
}
return getBufIfOpen()[pos++] & 0xff;
}
//读取字节至相应数组(private方法)
private int read1(byte[] b, int off, int len) throws IOException {
int avail = count - pos;
if (avail <= 0) {
/* If the requested length is at least as large as the buffer, and
if there is no mark/reset activity, do not bother to copy the
bytes into the local buffer. In this way buffered streams will
cascade harmlessly. */
if (len >= getBufIfOpen().length && markpos < 0) {
return getInIfOpen().read(b, off, len);
}
fill();
avail = count - pos;
if (avail <= 0) return -1;
}
int cnt = (avail < len) ? avail : len;
System.arraycopy(getBufIfOpen(), pos, b, off, cnt);
pos += cnt;
return cnt;
}
//读取相应字节至数组,为一个同步方法,线程安全
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;
if (n >= len)
return n;
// if not closed but no bytes available, return
InputStream input = in;
if (input != null && input.available() <= 0)
return n;
}
}
//跳过n个字节
public synchronized long skip(long n) throws IOException {
getBufIfOpen(); // Check for closed stream
if (n <= 0) {
return 0;
}
long avail = count - pos;
if (avail <= 0) {
// If no mark position set then don't keep in buffer
if (markpos <0)
return getInIfOpen().skip(n);
// Fill in buffer to save bytes for reset
fill();
avail = count - pos;
if (avail <= 0)
return 0;
}
long skipped = (avail < n) ? avail : n;
pos += skipped;
return skipped;
}
public synchronized int available() throws IOException {
int n = count - pos;
int avail = getInIfOpen().available();
return n > (Integer.MAX_VALUE - avail)
? Integer.MAX_VALUE
: n + avail;
}
public synchronized void mark(int readlimit) {
marklimit = readlimit;
markpos = pos;
}
public synchronized void reset() throws IOException {
getBufIfOpen(); // Cause exception if closed
if (markpos < 0)
throw new IOException("Resetting to invalid mark");
pos = markpos;
}
public boolean markSupported() {
return true;
}
public void close() throws IOException {
byte[] buffer;
while ( (buffer = buf) != null) {
if (bufUpdater.compareAndSet(this, buffer, null)) {
InputStream input = in;
in = null;
if (input != null)
input.close();
return;
}
// Else retry in case a new buf was CASed in fill()
}
}
}
BufferedOutputStream
public
class BufferedOutputStream extends FilterOutputStream {
//buffer数组
protected byte buf[];
//buffer中有效值
protected int count;
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];
}
//清空缓冲区
private void flushBuffer() throws IOException {
if (count > 0) {
out.write(buf, 0, count);
count = 0;
}
}
//写入一个字节至缓冲区
public synchronized void write(int b) throws IOException {
if (count >= buf.length) {
flushBuffer();
}
buf[count++] = (byte)b;
}
//写入一个字节数组
public synchronized void write(byte b[], int off, int len) throws IOException {
//如果需要写入的长度大于缓冲区大小,则先清空缓冲区(将缓冲区所有字节写出),再写出该字节。
if (len >= buf.length) {
/* If the request length exceeds the size of the output buffer,
flush the output buffer and then write the data directly.
In this way buffered streams will cascade harmlessly. */
flushBuffer();
out.write(b, off, len);
return;
}
//如果剩下的缓冲区容量放不下需要写入的字节长度,则把缓冲区字节写出
if (len > buf.length - count) {
flushBuffer();
}
//将相应字节数组复制至缓冲区
System.arraycopy(b, off, buf, count, len);
count += len;
}
//强制刷新缓冲,将缓冲内的数据写出至Output Stream
public synchronized void flush() throws IOException {
flushBuffer();
out.flush();
}
}