首页 > 基础资料 博客日记
BufferedInputStream类中的reset方法(reset方法使用技巧及常见问题)
2023-04-22 12:57:24基础资料围观998次
reset方法介绍及使用
BufferedInputStream的reset()方法用于将流的读取位置重置为指定的标记位置,以便再次读取该流。该方法可以撤消当前流状态中任何未读取的数据,但是它不能撤消已经读取的数据。
当创建BufferedInputStream时,可以通过调用mark()方法将当前流位置标记为一个特定的位置。在随后的操作中,如果需要重新从标记位置开始读取流,则可以调用()方法。如果未调mark()方法,则无法调用reset()方法。
注意的是,使用BufferInputStream的reset()方法并不代表所有的InputStream都持该操作。只有输入流支持标记和重置时,才可以使用这两个方法。
如果在调用reset()之后尚未调用过mark(),则会抛出InvalidMarkException异常。如果流已被关闭,则会抛出IOException异常。
下面是一个简单的示例代码展示reset()方法的使用:
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class BufferedInputStreamExample {
public static void main(String[] args) {
String filePath = "example.txt";
try {
InputStream inputStream = new FileInputStream(filePath); // 创建文件输入流
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream); // 将文件输入流包装成BufferedInputStream
System.out.println("初始位置:" + bufferedInputStream.read()); // 读取第一个字节并输出
System.out.println("当前位置:" + bufferedInputStream.read()); // 读取第二个字节并输出
bufferedInputStream.mark(0); // 标记当前位置
System.out.println("读到的数据:" + bufferedInputStream.read()); // 读取第三个字节并输出
System.out.println("调用 reset() 前:");
System.out.println("读到的数据:" + bufferedInputStream()); // 读取第个字节并输出(注意:此时下一次可读取的字节经变为第四个字节)
bufferedInputStream.reset(); // 将指针返回到标记的位置
System.out.println("调用 reset() 后:");
System.out.println("读到的数据:" + bufferedInputStream.read()); // 再次读取第三个字节并输出
bufferedInputStream.close(); // 关闭
} catch (IOException e) {
e.printStackTrace();
}
}
}运行结果如下:
初始位置:104 当前位置:101 读到的数据:108 调用 reset() 前: 读到的数据:111 调用 reset() 后: 读到的数据:108
在示例代码中,我们首先创建一个文件输入,并将其包装为BufferedInputStream。接着,我们读取了前三个字节,并在第三个字节处对BufferedInputStream做了标记。然后,我们再次读取一个字节并输出,此时下一次可读取的字节已经变为第四个字节。接着,我们调用reset()方法将指针返回到标记的位置,再次读取同样的字节。可以看到,第二次读取的结果与第一次读取的结果相同,BufferedInputStream的reset()方法成功将流的读取位置重置为了指定的标位置。
reset方法可能会出现的问题
使用reset()方法需要注意以下几个问题:
1. 是否支持reset()方法:不是所有的流都支持reset()方法。只有实现了mark()方法的流才能够调用reset()方法。如果尝试在一个无法重置的流上调用reset()方法,将会抛出IOException。
2. mark()方法的参数:当调用mark()方法时,需要传入一个参数来标识重置位置,这个参数的取值应该为非负整数。如果输入一个小于0的数,将会抛出IllegalArgumentException;如果超过了流中可存储的最大字节数,则会抛出IOException。
3. 标记位置的有效性:如果调用mark()方法后读取了一定量的数据,再调用reset()方法可能会失败。因为BufferedInputStream等缓冲输入流通常会使用一个内部的字节数组作为缓冲区,当缓冲区填满后,读取器将从底层输入流中读取数据直到缓冲区再次被填满。如果在此期间调用reset()方法,会导致相关的标记信息丢失,从而无法重置输入流。
4. 重置后的读取位置:调用reset()方法将硬性地将流的读取位置重置为之前调用mark()方法传递的位置。因此,在调用reset()方法之后,下一次读取操作将从指定位置开始读取,而不是从调用reset()方法之前读取的位置继续读取。
总之,在使用reset()方法时,需要保证流支持该方法,并且标记位置是有效的,否则将会抛出异常或者导致数据读取错误。此外,在缓冲输入流中使用reset()时,还需要对字节缓冲区的大小进行了解,以避免在调用reset()方法时发生异常情况。
下面演示当调用mark()方法后读取了一定量的数据,再调用reset()方法可能会失败的情况:
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
FileInputStream inputStream = new FileInputStream("example.txt");
BufferedInputStream bufferedInput = new BufferedInputStream(inputStream);
try {
// 在第6个字节处做一个标记
bufferedInput.mark(6);
// 读取前6个字节,此时标记有效
for (int i = 0; i 6; i++) {
bufferedInput.read();
}
// 尝试重置输入流,此时重置操作成功
bufferedInput.reset();
// 读取另外4个字节,此时流已经继续向后读取,
// 标记位置已经失效,无法再次使用reset()方法重置输入流
for (int i = 0; i 4; i++) {
bufferedInput.read();
}
// 尝试重置输入流,此时会抛出异常
bufferedInput.reset();
} catch (IOException e) {
System.out.println("抛出异常:" + e.getMessage());
} finally {
bufferedInput.close();
}
}
}在这段代码中,我们首先在输入流的第6个字节处做了一个标记,并成功将输入流重置回标记位置。然而,在我们接下来读取了4个字节后,尝试再次调用reset()方法时,程序抛出了IOException异常,即重置操作失败。
这是因为在我们读取完前6个字节之后,流继续向后读取,并可能将数据填充到内部缓冲区中。因此,当我们尝试使用reset()方法重置输入流时,标记位置已经失效它没有办法再次将流的读取位置恢复到最初的状态。
更多Java基础类的用法,请持续关注Java资料网,Java资料网专注为广大Java开发者提供各种Java资料。
标签:
相关文章
最新发布
- 使用 Word 模板占位符生成文档的技术方案实践
- java并发性能陷阱--伪共享
- keycloak~关于iframe方式对接keyclock的注意事项
- keycloak~keycloak14.0源代码二次开发
- 每日一题:第474场周赛 Q1. 找出缺失的元素
- 国产化Excel处理控件Spire.XLS教程:如何使用 Java 将 TXT 文本转换为 Excel 表格
- keycloak~关于跨域的iframe对接keycloak的分析
- 告别Minio管控繁琐!这款Java开源管理工具太香了
- 【行业案例】借助Vaadin全栈Java Web框架,实现仓储物流管理系统(WMS)现代化升级
- 技术面:SpringBoot(springboot的类加载和传统的双亲委派有什么区别、如何按顺序实例化Bean)


