昨天用到了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的大小默认是
private static int defaultCharBufferSize = 8192;
这个默认值可以通过构造函数
public BufferedReader(Reader in, int sz)
来指定。
关键的部分是fill方法的代码
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);
} while (n == 0);
if (n > 0) {
nChars = dst + n;
nextChar = dst;
}
}
第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 的缓存。
可以写程序来验证结论来验证一下
class a {
public static void main(String args[])// throws Exception
{
FileInputStream fis = null;
try {
fis = new FileInputStream("新建文本文档.txt");
InputStreamReader instream = new InputStreamReader(fis, "gbk"); BufferedReader br = new BufferedReader(instream, 20);//buffersize=20 for (int i=0; i<10; i++) {
br.read();
} br.mark(10);//markedChar=10, readAheadLimit = 10 20-10=10 buffersize-markedChar>=readAheadLimit ,所以抛出异常 for (int i=0; i<15; i++) {
br.read();
}
br.reset();
} catch(Exception e) {
System.out.println("在catch里面"+e);
} finally {
}
}
}//运行结果:在catch里面java.io.IOException: Mark invalid
import java.io.*;
import java.lang.Exception; class a {
public static void main(String args[])// throws Exception
{
FileInputStream fis = null;
try {
fis = new FileInputStream("新建文本文档.txt");
InputStreamReader instream = new InputStreamReader(fis, "gbk"); BufferedReader br = new BufferedReader(instream, 20);//buffersize=20 for (int i=0; i<10; i++) {
br.read();
} br.mark(11);//markedChar=10, readAheadLimit = 11 20-10=10 < 11 buffersize-markedChar<readAheadLimit ,所以不抛出异常 for (int i=0; i<15; i++) {
br.read();
}
br.reset();
} catch(Exception e) {
System.out.println("在catch里面"+e);
} finally {
}
}
}//程序运行后什么也不输出