BufferedReader和BufferedInputStream类似,都是内部维护一个数组,先把底层的input读入到内部数组,再对内部数组进行各种操作。其重要的函数有
- /**
- * Creates a buffering character-input stream that uses an input buffer of
- * the specified size.
- *
- * @param in
- * A Reader
- * @param sz
- * Input-buffer size
- *
- * @exception IllegalArgumentException
- * If sz is <= 0
- */
- public BufferedReader(Reader in, int sz) {
- super(in);
- if (sz <= 0)
- throw new IllegalArgumentException("Buffer size <= 0");
- this.in = in;
- cb = new char[sz];
- nextChar = nChars = 0; //nextChar代表下次要读取的位置,nChars表示总共的字符个数
- }
- /**
- * Reads a single character.
- *
- * @return The character read, as an integer in the range 0 to 65535 (
- * 0x00-0xffff), or -1 if the end of the stream has been
- * reached
- * @exception IOException
- * If an I/O error occurs
- */
- public int read() throws IOException {
- synchronized (lock) {
- ensureOpen();
- for (;;) {
- if (nextChar >= nChars) {
- fill(); //如果要读取的位置已经超过最大的字符数,那么需要调用fill()读入新的数据
- if (nextChar >= nChars) //如果读完还是大于,那么说明其实之前就已经到了input的结尾,所以返回-1
- return -1;
- }
- if (skipLF) {
- skipLF = false;
- if (cb[nextChar] == '\n') {
- nextChar++;
- continue;
- }
- }
- return cb[nextChar++]; //返回当前位置的数据,并把nextChar位置加1
- }
- }
- }
- /**
- * Fills the input buffer, taking the mark into account if it is valid.
- */
- private void fill() throws IOException {
- int dst;
- if (markedChar <= UNMARKED) {
- /* No mark */
- dst = 0;
- } else {
- /* Marked */
- int delta = nextChar - markedChar;
- if (delta >= readAheadLimit) {
- /* Gone past read-ahead limit: Invalidate mark */
- markedChar = INVALIDATED;
- readAheadLimit = 0;
- dst = 0;
- } else {
- if (readAheadLimit <= cb.length) {
- /* Shuffle in the current buffer */
- System.arraycopy(cb, markedChar, cb, 0, delta);
- markedChar = 0;
- dst = delta;
- } else {
- /* Reallocate buffer to accommodate read-ahead limit */
- char ncb[] = new char[readAheadLimit];
- System.arraycopy(cb, markedChar, ncb, 0, delta);
- cb = ncb;
- markedChar = 0;
- dst = delta;
- }
- nextChar = nChars = delta;
- }
- }
- int n;
- do {
- n = in.read(cb, dst, cb.length - dst); //从底层input读取数据到cb,cb中起始位置是dst, 读取的长度是cb的lenght减去起始位置dst
- } while (n == 0);
- if (n > 0) {
- nChars = dst + n;
- nextChar = dst; //把起始位置赋给nextChar
- }
- }
与BufferedInputStream不同的是,BufferedReader有个ReadLine方法,可以读取整行数据,
点击(此处)折叠或打开
- String readLine(boolean ignoreLF) throws IOException {
- StringBuffer s = null; //读取的数据最终放在这个s中,
- int startChar;
- synchronized (lock) {
- ensureOpen();
- boolean omitLF = ignoreLF || skipLF;
- bufferLoop: for (;;) {
- if (nextChar >= nChars)
- fill();
- if (nextChar >= nChars) { /* EOF */
- if (s != null && s.length() > 0)
- return s.toString(); //从这里返回,可能是因为读取的数据最后没有以\n或\r结束
- else
- return null; //从这里返回,是因为开始读的时候,就已经是input的末尾了,所以s本身就没有被初始化,只能返回null
- }
- boolean eol = false;
- char c = 0;
- int i;
- /* Skip a leftover '\n', if necessary */
- if (omitLF && (cb[nextChar] == '\n'))
- nextChar++;
- skipLF = false;
- omitLF = false;
- charLoop: for (i = nextChar; i < nChars; i++) {
- c = cb[i];
- if ((c == '\n') || (c == '\r')) {
- eol = true; //读到\n或者\r,那么说明读到了行尾
- break charLoop;
- }
- }
- startChar = nextChar;
- nextChar = i;
- if (eol) {
- String str;
- if (s == null) {
- str = new String(cb, startChar, i - startChar); //运行到这,s为null,说明是第一次循环中就读到了行尾。
- } else {
- s.append(cb, startChar, i - startChar); //运行到这,起码说明是第二次循环了,s里已经有了第一次读取的数据
- str = s.toString();
- }
- nextChar++;
- if (c == '\r') {
- skipLF = true;
- }
- return str; //运行到这说明读到了行尾,返回str
- }
- if (s == null)
- s = new StringBuffer(defaultExpectedLineLength);
- s.append(cb, startChar, i - startChar); //运行到这说明,读取了整个cb的数据,发现一直没有\n或者\r, 之后回到最初循环继续读取。
- }
- }
- }
有个问题,一直没搞懂 readAheadLimit 这个变量是干啥用的?
- public class BufferedReader extends Reader {
- private Reader in;
- private char cb[];
- private int nChars, nextChar;
- private static final int INVALIDATED = -2;
- private static final int UNMARKED = -1;
- private int markedChar = UNMARKED;
- private int readAheadLimit = 0; /* Valid only when markedChar > 0 */ ??????
- 。。。
- }
在mark函数中会设置它的值,在上面的fill()函数中会根据它的值来调整读取的数据多少和位置。
- /**
- * Marks the present position in the stream. Subsequent calls to reset()
- * will attempt to reposition the stream to this point.
- *
- * @param readAheadLimit
- * Limit on the number of characters that may be read while still
- * preserving the mark. An attempt to reset the stream after
- * reading characters up to this limit or beyond may fail. A
- * limit value larger than the size of the input buffer will
- * cause a new buffer to be allocated whose size is no smaller
- * than limit. Therefore large values should be used with care.
- *
- * @exception IllegalArgumentException
- * If readAheadLimit is < 0
- * @exception IOException
- * If an I/O error occurs
- */
- public void mark(int readAheadLimit) throws IOException {
- if (readAheadLimit < 0) {
- throw new IllegalArgumentException("Read-ahead limit < 0");
- }
- synchronized (lock) {
- ensureOpen();
- this.readAheadLimit = readAheadLimit;
- markedChar = nextChar;
- markedSkipLF = skipLF;
- }
- }
阅读(8014) | 评论(1) | 转发(0) |