本章内容包括3个部分:BufferedInputStream介绍,BufferedInputStream源码,以及BufferedInputStream使用示例。
BufferedInputStream 介绍
BufferedInputStream 是缓冲输入流。它继承于
BufferedInputStream 的作用是为另一个输入流添加一些功能,例如,提供“缓冲功能”以及支持“mark()标记”和“reset()重置方法”。
BufferedInputStream 本质上是通过一个内部缓冲区数组实现的。例如,在新建某输入流对应的BufferedInputStream后,当我们通过read()读取输入流的数据时,BufferedInputStream会将该输入流的数据分批的填入到缓冲区中。每当缓冲区中的数据被读完之后,输入流会再次填充数据缓冲区;如此反复,直到我们读完输入流数据位置。
BufferedInputStream 函数列表
BufferedInputStream(InputStream in)
BufferedInputStream(InputStream in,intsize)synchronized intavailable()voidclose()synchronized void mark(intreadlimit)booleanmarkSupported()synchronized intread()synchronized int read(byte[] buffer, int offset, intbyteCount)synchronized voidreset()synchronized long skip(long byteCount)
BufferedInputStream 源码分析(基于jdk1.7.40)
1 packagejava.io;2 importjava.util.concurrent.atomic.AtomicReferenceFieldUpdater;3
4 public class BufferedInputStream extendsFilterInputStream {5
6 //默认的缓冲大小是8192字节7 //BufferedInputStream 会根据“缓冲区大小”来逐次的填充缓冲区;8 //即,BufferedInputStream填充缓冲区,用户读取缓冲区,读完之后,BufferedInputStream会再次填充缓冲区。如此循环,直到读完数据...
9 private static int defaultBufferSize = 8192;10
11 //缓冲数组
12 protected volatile bytebuf[];13
14 //缓存数组的原子更新器。15 //该成员变量与buf数组的volatile关键字共同组成了buf数组的原子更新功能实现,16 //即,在多线程中操作BufferedInputStream对象时,buf和bufUpdater都具有原子性(不同的线程访问到的数据都是相同的)
17 private static final
18 AtomicReferenceFieldUpdater bufUpdater =
19 AtomicReferenceFieldUpdater.newUpdater20 (BufferedInputStream.class, byte[].class, "buf");21
22 //当前缓冲区的有效字节数。23 //注意,这里是指缓冲区的有效字节数,而不是输入流中的有效字节数。
24 protected intcount;25
26 //当前缓冲区的位置索引27 //注意,这里是指缓冲区的位置索引,而不是输入流中的位置索引。
28 protected intpos;29
30 //当前缓冲区的标记位置31 //markpos和reset()配合使用才有意义。操作步骤:32 //(01) 通过mark() 函数,保存pos的值到markpos中。33 //(02) 通过reset() 函数,会将pos的值重置为markpos。接着通过read()读取数据时,就会从mark()保存的位置开始读取。
34 protected int markpos = -1;35
36 //marklimit是标记的最大值。37 //关于marklimit的原理,我们在后面的fill()函数分析中会详细说明。这对理解BufferedInputStream相当重要。
38 protected intmarklimit;39
40 //获取输入流
41 private InputStream getInIfOpen() throwsIOException {42 InputStream input =in;43 if (input == null)44 throw new IOException("Stream closed");45 returninput;46 }47
48 //获取缓冲
49 private byte[] getBufIfOpen() throwsIOException {50 byte[] buffer =buf;51 if (buffer == null)52 throw new IOException("Stream closed");53 returnbuffer;54 }55
56 //构造函数:新建一个缓冲区大小为8192的BufferedInputStream
57 publicBufferedInputStream(InputStream in) {58 this(in, defaultBufferSize);59 }60
61 //构造函数:新建指定缓冲区大小的BufferedInputStream
62 public BufferedInputStream(InputStream in, intsize) {63 super(in);64 if (size <= 0) {65 throw new IllegalArgumentException("Buffer size <= 0");66 }67 buf = new byte[size];68 }69
70 //从“输入流”中读取数据,并填充到缓冲区中。71 //后面会对该函数进行详细说明!
72 private void fill() throwsIOException {73 byte[] buffer =getBufIfOpen();74 if (markpos < 0)75 pos = 0; /*no mark: throw away the buffer*/
76 else if (pos >= buffer.length) /*no room left in buffer*/
77 if (markpos > 0) { /*can throw away early part of the buffer*/
78 int sz = pos -markpos;79 System.arraycopy(buffer, markpos, buffer, 0, sz);80 pos =sz;81 markpos = 0;82 } else if