昨天用到了BufferedReader类里面mark(int readAheadLimit)方法,对于文档里面readAheadLimit的解释有些没弄懂,就翻开源码研究。具体的源码分析可以参见http://www.cnblogs.com/skywang12345/p/io_23.html ,这里直接给出结论。
当readAheadLimit的值小于等于BufferedReader里面缓存的大小buffersize时,如果mark(readAheadLimit)后再读取buffersize+1个字符,再reset()就会抛出异常,因为mark标记已经失效。
当readAheadLimit的值大于BufferedReader里面缓存的大小buffersize时,如果mark(readAheadLimit)后再读取readAheadLimit+1个字符,再reset()就会抛出异常,因为mark标记已经失效。
即 size = Math.max(readAheadLimit,buffersize),如果mark(readAheadLimit)后再读取size+1个字符,再reset()就会抛出异常,因为mark标记已经失效。
-----------------删除线部分不正确,下面的红字才是正确结论--------------------------------------
为什么会让mark失效?因为内存是有限的,当读取了很多字符后一直要存着标记就会迫使缓存最少保存从mark位置的那个字符到mark+readAheadLimit个字符之间的字符。所以抄了这个readAheadLimit,会失效。
buffersize的大小默认是
1 private static int defaultCharBufferSize = 8192;
这个默认值可以通过构造函数
public BufferedReader(Reader in, int sz)
来指定。
关键的部分是fill方法的代码
1 private void fill() throws IOException { 2 int dst; 3 if (markedChar <= UNMARKED) { 4 /* No mark */ 5 dst = 0; 6 } else { 7 /* Marked */ 8 int delta = nextChar - markedChar; 9 if (delta >= readAheadLimit) { 10 /* Gone past read-ahead limit: Invalidate mark */ 11 markedChar = INVALIDATED; 12 readAheadLimit = 0; 13 dst = 0; 14 } else { 15 if (readAheadLimit <= cb.length) { 16 /* Shuffle in the current buffer */ 17 System.arraycopy(cb, markedChar, cb, 0, delta); 18 markedChar = 0; 19 dst = delta; 20 } else { 21 /* Reallocate buffer to accommodate read-ahead limit */ 22 char ncb[] = new char[readAheadLimit]; 23 System.arraycopy(cb, markedChar, ncb, 0, delta); 24 cb = ncb; 25 markedChar = 0; 26 dst = delta; 27 } 28 nextChar = nChars = delta; 29 } 30 } 31 32 int n; 33 do { 34 n = in.read(cb, dst, cb.length - dst); 35 } while (n == 0); 36 if (n > 0) { 37 nChars = dst + n; 38 nextChar = dst; 39 } 40 }
第7行到第28行为关键部分,调用fill方法的时机是第一次读取时和缓存读取完后接着读取时,到底mark后读取超过readAheadLimit个字符是否会清除readAheadLimit,取决于buffersize-markedChar与readAheadLimit的大小关系,如果buffersize-markedChar>=readAheadLimit,那么超过readAheadLimit后reset会抛出异常,如果buffersize-markedChar<readAheadLimit那么超过readAheadLimit不会抛出异常,可以正常调用reset方法。这时候readAheadLimit的含义也就可以理解了即mark后再读取超过readAheadLimit说不是能正常的reset成功。buffersize的值在readAheadLimit > cb.length,即buffersize<readAheadLimit时读取完buffer会导致分配一个大小为readAheadLimit 的缓存。
可以写程序来验证结论来验证一下
1 class a { 2 public static void main(String args[])// throws Exception 3 { 4 FileInputStream fis = null; 5 try { 6 fis = new FileInputStream("新建文本文档.txt"); 7 InputStreamReader instream = new InputStreamReader(fis, "gbk"); 8 9 BufferedReader br = new BufferedReader(instream, 20);//buffersize=20 10 11 for (int i=0; i<10; i++) { 12 br.read(); 13 } 14 15 br.mark(10);//markedChar=10, readAheadLimit = 10 20-10=10 buffersize-markedChar>=readAheadLimit ,所以抛出异常 16 17 for (int i=0; i<15; i++) { 18 br.read(); 19 } 20 br.reset(); 21 } catch(Exception e) { 22 System.out.println("在catch里面"+e); 23 } finally { 24 } 25 } 26 }//运行结果:在catch里面java.io.IOException: Mark invalid
1 import java.io.*; 2 import java.lang.Exception; 3 4 class a { 5 public static void main(String args[])// throws Exception 6 { 7 FileInputStream fis = null; 8 try { 9 fis = new FileInputStream("新建文本文档.txt"); 10 InputStreamReader instream = new InputStreamReader(fis, "gbk"); 11 12 BufferedReader br = new BufferedReader(instream, 20);//buffersize=20 13 14 for (int i=0; i<10; i++) { 15 br.read(); 16 } 17 18 br.mark(11);//markedChar=10, readAheadLimit = 11 20-10=10 < 11 buffersize-markedChar<readAheadLimit ,所以不抛出异常 19 20 for (int i=0; i<15; i++) { 21 br.read(); 22 } 23 br.reset(); 24 } catch(Exception e) { 25 System.out.println("在catch里面"+e); 26 } finally { 27 } 28 } 29 }//程序运行后什么也不输出