InputStream之mark()_reset()
mark(): Marks the current position in this input stream.在此输入流中标记当前的位置。
reset(): Repositions this stream to the position at the time the <code>mark</code> method was last called on this input stream.将此流重新定位到对此输入流最后调用 mark 方法时的位置。
BufferedInputStream的mark和reset方法:
mark方法
public synchronized void mark(int readlimit) {
marklimit = readlimit; //marklimit表示标记当前位置,并保证在mark以后最多可以读取readlimit字节数据,mark标记仍有效。如果在mark后读取超过readlimit字节数据,mark标记就会失效,调用reset()方法会有异常
markpos = pos; //把当前的位置设置标记位置,当调用reset方法时,会回到这个位置
}
reset方法
public synchronized void reset() throws IOException {
getBufIfOpen(); // Cause exception if closed
if (markpos < 0)
throw new IOException("Resetting to invalid mark");
pos = markpos;
}
测试程序:
@Test
public void test4() throws Exception {
//512默认缓冲流数组buf的大小
InputStream in = new BufferedInputStream(new FileInputStream("e:\\key\\hello.txt"), 512);
if (!in.markSupported()) {
System.out.println("此流不支持mark方法");
return;
} else {
in.mark(12); //当前的pos为0,在此时标记,当调用reset方法时,会回到流的开始,12表示当最多读取12个字节时,mark标记会失效。但实际情况不是如此。
}
int bytesRead = 0;
byte[] buffer = new byte[12];
//从文件中按字节读取内容,到文件尾部时read方法将返回-1
while ((bytesRead = in.read(buffer)) != -1) {
//将读取的字节转为字符串对象
String chunk = new String(buffer, 0, bytesRead);
System.out.print(chunk);
}
/**
* 实际效果不是如此,多情况下在BufferedInputStream类中调用mark(int readlimit)方法后,
* 即使读取超过readlimit字节的数据,mark标记仍有效,仍然能正确调用reset方法重置。
* 事实上,mark在JAVA中的实现是和缓冲区相关的。\
* 只要缓冲区够大,mark后读取的数据没有超出缓冲区的大小,mark标记就不会失效。
* 如果不够大,mark后又读取了大量的数据,导致缓冲区更新,原来标记的位置自然找不到了。
*/
//将此流重新定位到对此输入流最后调用 mark 方法时的位置。
in.reset();
while ((bytesRead = in.read(buffer)) != -1) {
//将读取的字节转为字符串对象
String chunk = new String(buffer, 0, bytesRead);
System.out.print(chunk);
}
}
附:BufferedInputStream
BufferedInputStream 的作用是为另一个输入流添加一些功能,例如,提供“缓冲功能”以及支持“mark()标记”和“reset()重置方法”。
BufferedInputStream 本质上是通过一个内部缓冲区数组实现的。例如,在新建某输入流对应的BufferedInputStream后,当我们通过read()读取输入流的数据时,BufferedInputStream会将该输入流的数据分批的填入到缓冲区中。每当缓冲区中的数据被读完之后,输入流会再次填充数据缓冲区;如此反复,直到我们读完输入流数据位置。