1 packagejava.io;2
3 public class BufferedReader extendsReader {4
5 privateReader in;6
7 //字符缓冲区
8 private charcb[];9 //nChars 是cb缓冲区中字符的总的个数10 //nextChar 是下一个要读取的字符在cb缓冲区中的位置
11 private intnChars, nextChar;12
13 //表示“标记无效”。它与UNMARKED的区别是:14 //(01) UNMARKED 是压根就没有设置过标记。15 //(02) 而INVALIDATED是设置了标记,但是被标记位置太长,导致标记无效!
16 private static final int INVALIDATED = -2;17 //表示没有设置“标记”
18 private static final int UNMARKED = -1;19 //“标记”
20 private int markedChar =UNMARKED;21 //“标记”能标记位置的最大长度
22 private int readAheadLimit = 0; /*Valid only when markedChar > 0*/
23
24 //skipLF(即skip Line Feed)是“是否忽略换行符”标记
25 private boolean skipLF = false;26
27 //设置“标记”时,保存的skipLF的值
28 private boolean markedSkipLF = false;29
30 //默认字符缓冲区大小
31 private static int defaultCharBufferSize = 8192;32 //默认每一行的字符个数
33 private static int defaultExpectedLineLength = 80;34
35 //创建“Reader”对应的BufferedReader对象,sz是BufferedReader的缓冲区大小
36 public BufferedReader(Reader in, intsz) {37 super(in);38 if (sz <= 0)39 throw new IllegalArgumentException("Buffer size <= 0");40 this.in =in;41 cb = new char[sz];42 nextChar = nChars = 0;43 }44
45 //创建“Reader”对应的BufferedReader对象,默认的BufferedReader缓冲区大小是8k
46 publicBufferedReader(Reader in) {47 this(in, defaultCharBufferSize);48 }49
50 //确保“BufferedReader”是打开状态
51 private void ensureOpen() throwsIOException {52 if (in == null)53 throw new IOException("Stream closed");54 }55
56 //填充缓冲区函数。有以下两种情况被调用:57 //(01) 缓冲区没有数据时,通过fill()可以向缓冲区填充数据。58 //(02) 缓冲区数据被读完,需更新时,通过fill()可以更新缓冲区的数据。
59 private void fill() throwsIOException {60 //dst表示“cb中填充数据的起始位置”。
61 intdst;62 if (markedChar <=UNMARKED) {63 //没有标记的情况,则设dst=0。
64 dst = 0;65 } else{66 //delta表示“当前标记的长度”,它等于“下一个被读取字符的位置”减去“标记的位置”的差值;
67 int delta = nextChar -markedChar;68 if (delta >=readAheadLimit) {69 //若“当前标记的长度”超过了“标记上限(readAheadLimit)”,70 //则丢弃标记!
71 markedChar =INVALIDATED;72 readAheadLimit = 0;73 dst = 0;74 } else{75 if (readAheadLimit <=cb.length) {76 //若“当前标记的长度”没有超过了“标记上限(readAheadLimit)”,77 //并且“标记上限(readAheadLimit)”小于/等于“缓冲的长度”;78 //则先将“下一个要被读取的位置,距离我们标记的置符的距离”间的字符保存到cb中。
79 System.arraycopy(cb, markedChar, cb, 0, delta);80 markedChar = 0;81 dst =delta;82 } else{83 //若“当前标记的长度”没有超过了“标记上限(readAheadLimit)”,84 //并且“标记上限(readAheadLimit)”大于“缓冲的长度”;85 //则重新设置缓冲区大小,并将“下一个要被读取的位置,距离我们标记的置符的距离”间的字符保存到cb中。
86 char ncb[] = new char[readAheadLimit];87 System.arraycopy(cb, markedChar, ncb, 0, delta);88 cb =ncb;89 markedChar = 0;90 dst =delta;91 }92 //更新nextChar和nChars
93 nextChar = nChars =delta;94 }95 }96
97 intn;98 do{99 //从“in”中读取数据,并存储到字符数组cb中;100 //从cb的dst位置开始存储,读取的字符个数是cb.length - dst101 //n是实际读取的字符个数;若n==0(即一个也没读到),则继续读取!
102 n = in.read(cb, dst, cb.length -dst);103 } while (n == 0);104
105 //如果从“in”中读到了数据,则设置nChars(cb中字符的数目)=dst+n,106 //并且nextChar(下一个被读取的字符的位置)=dst。
107 if (n > 0) {108 nChars = dst +n;109 nextChar =dst;110 }111 }112
113 //从BufferedReader中读取一个字符,该字符以int的方式返回
114 public int read() throwsIOException {115 synchronized(lock) {116 ensureOpen();117 for(;;) {118 //若“缓冲区的数据已经被读完”,119 //则先通过fill()更新缓冲区数据
120 if (nextChar >=nChars) {121 fill();122 if (nextChar >=nChars)123 return -1;124 }125 //若要“忽略换行符”,126 //则对下一个字符是否是换行符进行处理。
127 if(skipLF) {128 skipLF = false;129 if (cb[nextChar] == '\n') {130 nextChar++;131 continue;132 }133 }134 //返回下一个字符
135 return cb[nextChar++];136 }137 }138 }139
140 //将缓冲区中的数据写入到数组cbuf中。off是数组cbuf中的写入起始位置,len是写入长度
141 private int read1(char[] cbuf, int off, int len) throwsIOException {142 //若“缓冲区的数据已经被读完”,则更新缓冲区数据。
143 if (nextChar >=nChars) {144 if (len >= cb.length && markedChar <= UNMARKED && !skipLF) {145 returnin.read(cbuf, off, len);146 }147 fill();148 }149 //若更新数据之后,没有任何变化;则退出。
150 if (nextChar >= nChars) return -1;151 //若要“忽略换行符”,则进行相应处理
152 if(skipLF) {153 skipLF = false;154 if (cb[nextChar] == '\n') {155 nextChar++;156 if (nextChar >=nChars)157 fill();158 if (nextChar >=nChars)159 return -1;160 }161 }162 //拷贝字符操作
163 int n = Math.min(len, nChars -nextChar);164 System.arraycopy(cb, nextChar, cbuf, off, n);165 nextChar +=n;166 returnn;167 }168
169 //对read1()的封装,添加了“同步处理”和“阻塞式读取”等功能
170 public int read(char cbuf[], int off, int len) throwsIOException {171 synchronized(lock) {172 ensureOpen();173 if ((off < 0) || (off > cbuf.length) || (len < 0) ||
174 ((off + len) > cbuf.length) || ((off + len) < 0)) {175 throw newIndexOutOfBoundsException();176 } else if (len == 0) {177 return 0;178 }179
180 int n =read1(cbuf, off, len);181 if (n <= 0) returnn;182 while ((n < len) &&in.ready()) {183 int n1 = read1(cbuf, off + n, len -n);184 if (n1 <= 0) break;185 n +=n1;186 }187 returnn;188 }189 }190
191 //读取一行数据。ignoreLF是“是否忽略换行符”
192 String readLine(boolean ignoreLF) throwsIOException {193 StringBuffer s = null;194 intstartChar;195
196 synchronized(lock) {197 ensureOpen();198 boolean omitLF = ignoreLF ||skipLF;199
200 bufferLoop:201 for(;;) {202
203 if (nextChar >=nChars)204 fill();205 if (nextChar >= nChars) { /*EOF*/
206 if (s != null && s.length() > 0)207 returns.toString();208 else
209 return null;210 }211 boolean eol = false;212 char c = 0;213 inti;214
215 /*Skip a leftover '\n', if necessary*/
216 if (omitLF && (cb[nextChar] == '\n'))217 nextChar++;218 skipLF = false;219 omitLF = false;220
221 charLoop:222 for (i = nextChar; i < nChars; i++) {223 c =cb[i];224 if ((c == '\n') || (c == '\r')) {225 eol = true;226 breakcharLoop;227 }228 }229
230 startChar =nextChar;231 nextChar =i;232
233 if(eol) {234 String str;235 if (s == null) {236 str = new String(cb, startChar, i -startChar);237 } else{238 s.append(cb, startChar, i -startChar);239 str =s.toString();240 }241 nextChar++;242 if (c == '\r') {243 skipLF = true;244 }245 returnstr;246 }247
248 if (s == null)249 s = newStringBuffer(defaultExpectedLineLength);250 s.append(cb, startChar, i -startChar);251 }252 }253 }254
255 //读取一行数据。不忽略换行符
256 public String readLine() throwsIOException {257 return readLine(false);258 }259
260 //跳过n个字符
261 public long skip(long n) throwsIOException {262 if (n < 0L) {263 throw new IllegalArgumentException("skip value is negative");264 }265 synchronized(lock) {266 ensureOpen();267 long r =n;268 while (r > 0) {269 if (nextChar >=nChars)270 fill();271 if (nextChar >= nChars) /*EOF*/
272 break;273 if(skipLF) {274 skipLF = false;275 if (cb[nextChar] == '\n') {276 nextChar++;277 }278 }279 long d = nChars -nextChar;280 if (r <=d) {281 nextChar +=r;282 r = 0;283 break;284 }285 else{286 r -=d;287 nextChar =nChars;288 }289 }290 return n -r;291 }292 }293
294 //“下一个字符”是否可读
295 public boolean ready() throwsIOException {296 synchronized(lock) {297 ensureOpen();298
299 //若忽略换行符为true;300 //则判断下一个符号是否是换行符,若是的话,则忽略
301 if(skipLF) {302 if (nextChar >= nChars &&in.ready()) {303 fill();304 }305 if (nextChar
315 //始终返回true。因为BufferedReader支持mark(), reset()
316 public booleanmarkSupported() {317 return true;318 }319
320 //标记当前BufferedReader的下一个要读取位置。关于readAheadLimit的作用,参考后面的说明。
321 public void mark(int readAheadLimit) throwsIOException {322 if (readAheadLimit < 0) {323 throw new IllegalArgumentException("Read-ahead limit < 0");324 }325 synchronized(lock) {326 ensureOpen();327 //设置readAheadLimit
328 this.readAheadLimit =readAheadLimit;329 //保存下一个要读取的位置
330 markedChar =nextChar;331 //保存“是否忽略换行符”标记
332 markedSkipLF =skipLF;333 }334 }335
336 //重置BufferedReader的下一个要读取位置,337 //将其还原到mark()中所保存的位置。
338 public void reset() throwsIOException {339 synchronized(lock) {340 ensureOpen();341 if (markedChar < 0)342 throw new IOException((markedChar ==INVALIDATED)343 ? "Mark invalid"
344 : "Stream not marked");345 nextChar =markedChar;346 skipLF =markedSkipLF;347 }348 }349
350 public void close() throwsIOException {351 synchronized(lock) {352 if (in == null)353 return;354 in.close();355 in = null;356 cb = null;357 }358 }359 }