昨天用到了BufferedReader類裏面mark(int readAheadLimit)方法,對於文檔裏面readAheadLimit的解釋有些沒弄懂,就翻開源碼研究。具體的源碼分析能夠參見http://www.cnblogs.com/skywang12345/p/io_23.html ,這裏直接給出結論。html
當readAheadLimit的值小於等於BufferedReader裏面緩存的大小buffersize時,若是mark(readAheadLimit)後再讀取buffersize+1個字符,再reset()就會拋出異常,由於mark標記已經失效。java
當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,會失效。spa
buffersize的大小默認是code
1 private static int defaultCharBufferSize = 8192;
這個默認值能夠經過構造函數htm
public BufferedReader(Reader in, int sz)
來指定。blog
關鍵的部分是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 }//程序運行後什麼也不輸出