Java中InputStream重复使用问题的几种解决方案
作者:ecexy78041
在Java开发中,InputStream是用于读取字节流的类,在许多场景下,我们可能需要重复读取InputStream中的数据,这篇文章主要介绍了Java中InputStream重复使用问题的几种解决方案,需要的朋友可以参考下
前言
在Java中,InputStream通常设计为"一次性"使用,读取后流会到达末尾,再次读取时会返回-1或抛出异常。以下是几种实现InputStream重复使用的方法:
1. 使用mark()和reset()方法(适用于支持标记的流)
java
import java.io.*;
public class InputStreamReuser {
public static void main(String[] args) throws IOException {
String data = "Hello World";
InputStream inputStream = new ByteArrayInputStream(data.getBytes());
// 第一次读取前标记
if (inputStream.markSupported()) {
inputStream.mark(0); // 参数是readlimit,0表示不限制
}
// 第一次读取
System.out.println("第一次读取:");
readAndPrint(inputStream);
// 重置流
if (inputStream.markSupported()) {
inputStream.reset();
}
// 第二次读取
System.out.println("第二次读取:");
readAndPrint(inputStream);
}
private static void readAndPrint(InputStream is) throws IOException {
int content;
while ((content = is.read()) != -1) {
System.out.print((char) content);
}
System.out.println();
}
}2. 将流内容缓存到字节数组(最可靠方法)
java
import java.io.*;
public class InputStreamCacher {
public static void main(String[] args) throws IOException {
InputStream originalStream = new FileInputStream("example.txt");
// 将流内容缓存到字节数组
byte[] bytes = readAllBytes(originalStream);
originalStream.close();
// 创建可重复使用的流
InputStream reusableStream1 = new ByteArrayInputStream(bytes);
InputStream reusableStream2 = new ByteArrayInputStream(bytes);
// 使用流1
System.out.println("第一次使用:");
readAndPrint(reusableStream1);
// 使用流2
System.out.println("第二次使用:");
readAndPrint(reusableStream2);
}
private static byte[] readAllBytes(InputStream is) throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
byte[] data = new byte[1024];
int nRead;
while ((nRead = is.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
return buffer.toByteArray();
}
private static void readAndPrint(InputStream is) throws IOException {
int content;
while ((content = is.read()) != -1) {
System.out.print((char) content);
}
System.out.println();
}
}3. 使用Apache Commons IO的IOUtils(简化代码)
java
import org.apache.commons.io.IOUtils;
import java.io.*;
public class CommonsIOExample {
public static void main(String[] args) throws IOException {
InputStream originalStream = new FileInputStream("example.txt");
// 将流转换为字节数组
byte[] bytes = IOUtils.toByteArray(originalStream);
originalStream.close();
// 创建可重复使用的流
InputStream reusableStream1 = new ByteArrayInputStream(bytes);
InputStream reusableStream2 = new ByteArrayInputStream(bytes);
// 使用流
System.out.println("第一次使用: " + IOUtils.toString(reusableStream1, "UTF-8"));
System.out.println("第二次使用: " + IOUtils.toString(reusableStream2, "UTF-8"));
}
}4. 自定义可重置的InputStream包装器
java
import java.io.*;
public class ResettableInputStream extends InputStream {
private final InputStream original;
private InputStream current;
private byte[] buffer;
private boolean buffered = false;
public ResettableInputStream(InputStream original) {
this.original = original;
this.current = original;
}
@Override
public int read() throws IOException {
return current.read();
}
public void resetStream() throws IOException {
if (!buffered) {
// 第一次重置时缓存内容
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] data = new byte[1024];
int nRead;
while ((nRead = original.read(data, 0, data.length)) != -1) {
baos.write(data, 0, nRead);
}
buffer = baos.toByteArray();
buffered = true;
}
current = new ByteArrayInputStream(buffer);
}
@Override
public void close() throws IOException {
original.close();
if (buffered && current != null) {
current.close();
}
}
}
// 使用示例
public class Main {
public static void main(String[] args) throws IOException {
ResettableInputStream ris = new ResettableInputStream(new FileInputStream("example.txt"));
// 第一次读取
System.out.println("第一次读取:");
readAndPrint(ris);
// 重置
ris.resetStream();
// 第二次读取
System.out.println("第二次读取:");
readAndPrint(ris);
ris.close();
}
private static void readAndPrint(InputStream is) throws IOException {
int content;
while ((content = is.read()) != -1) {
System.out.print((char) content);
}
System.out.println();
}
}注意事项
内存考虑:缓存整个流到内存中可能不适合处理非常大的文件
资源释放:确保在所有使用完成后关闭流
性能影响:重复读取相同的流内容会有额外的内存开销
网络流:对于网络流,通常无法重置,必须先缓存内容
标记支持:不是所有
InputStream实现都支持mark()和reset()
总结
到此这篇关于Java中InputStream重复使用问题的几种解决方案的文章就介绍到这了,更多相关Java中InputStream重复使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
