关于BufferedInputStream类的mark与reset方法的一个bug的问题.txt
sylilzy@gmail.com 施祖阳 http://www.shizuyang.cn
2010-7-7 13:20:26 星期三
最近在调试程序时发现BufferedInputStream类的mark与reset方法存在一个bug,重现方式如下:
import java.io.BufferedInputStream;
import java.io.FileInputStream;
public class BugTest {
/**
* @param args
*/
static public void main(String[] p) throws Exception {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("e://temp//a.txt"));
int available = bis.available();
System.out.println("available:" + available);
// ---
int markLimit = available;
bis.mark(markLimit);
System.out.println("---mark:" + markLimit);
byte[] temp = new byte[available];
bis.read(temp);
System.out.println("---read:" + available);
System.out.println("---read one byte:" + bis.read());
bis.reset();
System.out.println("reset ok!");
bis.close();
}
}
在以上类运行时,如果e://temp//a.txt文件的大小在8192字节以上,则运行结果如下:
available:8384
---mark:8384
---read:8384
---read one byte:-1
Exception in thread "main" java.io.IOException: Resetting to invalid mark
at java.io.BufferedInputStream.reset(Unknown Source)
at com.BugTest.main(BugTest.java:22)
如果e://temp//a.txt文件的大小在8192字节以下,则不会有此异常。
为了分析问题产生的原因,我写了如下一个类来显示BufferedInputStream类的相关信息:
import java.io.BufferedInputStream;
import java.io.InputStream;
public class MyBuffer extends BufferedInputStream {
public MyBuffer(InputStream in, int size) {
super(in, size);
// TODO Auto-generated constructor stub
}
public MyBuffer(InputStream in) {
super(in);
// TODO Auto-generated constructor stub
}
public int getMarklimit() {
return marklimit;
}
public int getMarkPosition() {
return markpos;
}
public int getBufferLength() {
return buf.length;
}
}
测试类修改如下:
import java.io.*;
import java.util.regex.Pattern;
/**
* @author shizy TODO To change the template for this generated type comment go
* to Window - Preferences - Java - Code Style - Code Templates
*/
public class Test {
static public void main(String[] p) throws Exception {
MyBuffer bis = new MyBuffer(new FileInputStream("e://temp//a.txt"));
int available = bis.available();
System.out.println("available:" + available);
System.out.println("getBufferLength:" + bis.getBufferLength());
System.out.println("getMarklimit:" + bis.getMarklimit());
System.out.println("getMarkPosition:" + bis.getMarkPosition());
// ---
int markLimit = available;
bis.mark(markLimit);
System.out.println("---mark:" + markLimit);
System.out.println("getBufferLength:" + bis.getBufferLength());
System.out.println("getMarklimit:" + bis.getMarklimit());
System.out.println("getMarkPosition:" + bis.getMarkPosition());
byte[] temp = new byte[available];
bis.read(temp);
System.out.println("---read:" + available);
System.out.println("getBufferLength:" + bis.getBufferLength());
System.out.println("getMarklimit:" + bis.getMarklimit());
System.out.println("getMarkPosition:" + bis.getMarkPosition());
System.out.println("---read one byte:" + bis.read());
System.out.println("getBufferLength:" + bis.getBufferLength());
System.out.println("getMarklimit:" + bis.getMarklimit());
System.out.println("getMarkPosition:" + bis.getMarkPosition());
bis.reset();
System.out.println("reset ok!");
bis.close();
}
}
则运行结果如下:
available:8384
getBufferLength:8192
getMarklimit:0
getMarkPosition:-1
---mark:8384
getBufferLength:8192
getMarklimit:8384
getMarkPosition:0
---read:8384
getBufferLength:8384
getMarklimit:8384
getMarkPosition:0
---read one byte:-1
getBufferLength:8384
getMarklimit:8384
getMarkPosition:-1
Exception in thread "main" java.io.IOException: Resetting to invalid mark
at java.io.BufferedInputStream.reset(Unknown Source)
at com.Test.main(Test.java:41)
可见,在输出了“---read:8384”后,BufferLength变成了与Marklimit一样的大小,但在"---read one byte:-1"后,MarkPosition变成了-1,导致了reset时出错。
解决办法有三种:
1.增加BufferedInputStream的BufferLength,在上例中,增加到8385则可解决问题。但此大小需要由输入流的数据量解定,此方法并不太可行。
2.改变markLimit大小。将int markLimit = available;修改为:int markLimit = available+1;。采用这种方式,则上例运行结果如下:
available:8384
getBufferLength:8192
getMarklimit:0
getMarkPosition:-1
---mark:8385
getBufferLength:8192
getMarklimit:8385
getMarkPosition:0
---read:8384
getBufferLength:8385
getMarklimit:8385
getMarkPosition:0
---read one byte:-1
getBufferLength:8385
getMarklimit:8385
getMarkPosition:0
reset ok!
3.不要在流数据结束之后再调用bis.read方法,这种方法并不能完全保证不出问题,因为流数据是否结束,必须要通过read的返回值才能知道。
看来,此问题的出现情况是当BufferLength刚好与从输入流读入的数据相等时(缓冲区会随着marklimit大小增长),如果再读入数据,即时此时未读入数据,则也会认为超过了Marklimit限制,则reset会抛出异常。
注:
jdk版本:
java version "1.6.0_05"
Java(TM) SE Runtime Environment (build 1.6.0_05-b13)
Java HotSpot(TM) Client VM (build 10.0-b19, mixed mode, sharing)