前面已经学习了FilterInputStream与FilterOutputStream。文章中到了FilterInputStream与FilterOutputStream的子类可进一步重写父类方法中的一些方法,来提供装饰功能。今天就来介绍下它们子类中的BufferedInputStream与BufferedOutputStream。
BufferedInputStream是缓冲输入流,作用是为另一个输入流添加一些功能,比如缓冲输入功能以及支持mark和reset方法的能力。在创建BufferedInputStream时,会在内存中创建一个内部缓冲区数组。在读取或跳过流中的字节时,可根据需要从包含的输入流一次性填充多个字节到该内部缓冲区。当程序需要读取字节时,直接从内部缓冲区中读取。当内部缓冲区中数据被读完后,会再次从包含的输入流一次性填充多个字节到该内部缓冲区。mark操作会记录输入流中的某个点,reset操作使得在从输入流中获取新字节之前,再次读取自最后一次mark操作后读取的所有字节。
BufferedOutputStream是缓冲输出流,通过设置这种输出流,应用程序就可以将各个字节写入底层输出流中,而不必针对每次字节写入调用底层系统。
下面先介绍下BufferedInputStream。
BufferedInputStream
public class BufferedInputStream extends FilterInputStream {
//缓冲区默认的默认大小
private static int DEFAULT_BUFFER_SIZE = 8192;
/**
* 分派给arrays的最大容量
* 为什么要减去8呢?
* 因为某些VM会在数组中保留一些头字,尝试分配这个最大存储容量,
* 可能会导致array容量大于VM的limit,最终导致OutOfMemoryError。
*/
private static int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
/**
* 存放数据的内部缓冲数组。
* 当有必要时,可能会被另一个不同容量的数组替代。
*/
protected volatile byte buf[];
/**
* 为缓冲区提供compareAndSet的原子更新器。
* 这是很有必要的,因为关闭操作可以使异步的。我们使用非空的缓冲区数组作为流被关闭的指示器。
* 该成员变量与buf数组的volatile关键字共同作用,实现了当在多线程环境中操作BufferedInputStream对象时,buf和bufUpdater都具有原子性。
*/
private static final
AtomicReferenceFieldUpdater<BufferedInputStream, byte[]> bufUpdater =
AtomicReferenceFieldUpdater.newUpdater
(BufferedInputStream.class, byte[].class, "buf");
/**
* 缓冲区中的字节数。
*/
protected int count;
/**
* 缓冲区当前位置的索引
*/
protected int pos;
/**
* 最后一次调用mark方法时pos字段的值。
*/
protected int markpos = -1;
/**
* 调用mark方法后,在后续调用reset方法失败之前所允许的最大提前读取量。
* markpos的最大值
*/
protected int marklimit;
/**
* 获取输入流。
* 判断输入流是否为null,如果为null,抛出异常,否则返回输入流。
*/
private InputStream getInIfOpen() throws IOException {
InputStream input = in;
if (input == null)
throw new IOException("Stream closed");
return input;
}
/**
* 获取缓冲区数组。
* 检查缓冲区数组是否为null,如果为null,抛出异常,否则返回缓冲区数组。
*/
private byte[] getBufIfOpen() throws IOException {
byte[] buffer = buf;
if (buffer == null)
throw new IOException("Stream closed");
return buffer;
}
/**
* 构造方法之一
* 创建一个缓冲区大小为DEFAULT_BUFFER_SIZE的BufferedInputStream。
*/
public BufferedInputStream(InputStream in) {
this(in, DEFAULT_BUFFER_SIZE);
}
/**
* 构造方法之一。
* 创建一个缓冲区大小为size的BufferedInputStream。 *
*/
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)// case1:缓冲区没有被标记。如果缓冲区被标记,那么markpos肯定大于等于0
pos = 0;:
else if (pos >= buffer.length) //缓冲区被标记,且缓冲器已满。pos >= buffer.length说明缓冲区已满。
if (