Java中InputStream重复使用问题的几种解决方案

 更新时间:2025年08月09日 14:06:42   作者: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重复使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java继承关系中构造器的使用详解

    Java继承关系中构造器的使用详解

    本文介绍了继承关系中构造器的使用要点,创建子类对象时,必须先调用父类构造器实现初始化,若父类无参构造器被覆盖,子类需用super显式调用父类构造器,且super须写在构造器首行,感兴趣的朋友跟随小编一起看看吧
    2025-10-10
  • spring aop底层原理及如何实现

    spring aop底层原理及如何实现

    这篇文章主要介绍了spring aop底层原理及如何实现,帮助大家更好的理解和学习使用spring aop,感兴趣的朋友可以了解下
    2021-04-04
  • JDK(免安装)各种版本下载及配置详细图文教程

    JDK(免安装)各种版本下载及配置详细图文教程

    这篇文章主要给大家介绍了关于JDK(免安装)各种版本下载及配置的相关资料,文中通过图文介绍的非常详细,对大家的学习或者工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2024-07-07
  • 使用SpringBoot找不到Mapper的Bean问题及解决

    使用SpringBoot找不到Mapper的Bean问题及解决

    这篇文章主要介绍了使用SpringBoot找不到Mapper的Bean问题及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2026-04-04
  • eclipse创建java项目并运行的详细教程讲解

    eclipse创建java项目并运行的详细教程讲解

    eclipse是java开发的ide工具,是大部分java开发人员的首选开发工具,可是对于一些新Java人员来说,不清楚eclipse怎么运行项目?这篇文章主要给大家介绍了关于eclipse创建java项目并运行的相关资料,需要的朋友可以参考下
    2023-04-04
  • java中Consumer接口的使用教程详解

    java中Consumer接口的使用教程详解

    Java 8 引入了 java.util.function 包,其中包含了一些常用的函数式接口,Consumer 接口是其中一个函数式接口,用于表示接受一个输入参数并执行某种操作的操作者,下面我们就来学习一下他的具体使用吧
    2023-12-12
  • Spring Boot 快速集成 Redis的方法

    Spring Boot 快速集成 Redis的方法

    这篇文章主要介绍了Spring Boot 如何快速集成 Redis,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-07-07
  • Java 14 发布了,你还会使用Lombok?

    Java 14 发布了,你还会使用Lombok?

    2020年3月17日发布,Java正式发布了JDK 14 ,目前已经可以开放下载。在JDK 14中,共有16个新特性,本文主要来介绍其中的一个特性:JEP 359: Records,需要的朋友可以参考下
    2020-04-04
  • mybatis参数类型不匹配错误argument type mismatch的处理方案

    mybatis参数类型不匹配错误argument type mismatch的处理方案

    这篇文章主要介绍了mybatis参数类型不匹配错误argument type mismatch的处理方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-01-01
  • mybatis-plus分页无效问题解决

    mybatis-plus分页无效问题解决

    本文主要介绍了mybatis-plus分页无效问题解决,原因是配置分页插件的版本问题,旧版本和新版本的MyBatis-Plus需要不同的分页配置,感兴趣的可以了解一下
    2025-03-03

最新评论