对【InputStream流只能被读取一次】的理解

问题复现

  1. InputStream流只能被读取一次,一但被读取出来后,再无法再次读取
  2. 示例
@Slf4j
public class CheckInputStream {
    public static void main(String[] args) {
        try (
                InputStream in = new FileInputStream("logs.log");
        ) {

            // 读取InputStream中数据
            byte[] read = read(in);
            String s = new String(read);
            log.info("第一次内容为:{}", s);

            // 再次尝试读取InputStream流中数据
            byte[] read2 = read(in);
            String s2 = new String(read2);
            log.info("第二次读取内容为:{}", s2);
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static byte[] read(InputStream in) throws IOException {
        int available = in.available();
        byte[] bytes = new byte[available];
        in.read(bytes);
        return bytes;
    }
}
  1. 输出结果:从下图可以看出第二次输出内容为空 在这里插入图片描述

原因

  1. 网络连接中的数据通常是通过InputStream读取的。虽然InputStream本身并不限制只能读取一次,但是在网络连接中,一旦数据被读取,它就会被消耗掉,因此无法再次读取相同的数据。这是因为网络连接中的数据是通过数据包进行传输的,一旦数据包被读取,它就会从网络缓冲区中移除,无法再次读取。即使使用mark()和reset()方法,也无法保证能够重新读取之前的数据,因为网络连接的数据包可能已经被丢弃或者移动到了下一个位置。
  2. 文件读取,InputStream流只能读取一次是因为在读取数据的过程中,流的指针会逐渐向文件的末尾移动。一旦指针到达了文件的末尾,再次读取数据时就无法再次从文件的开头开始读取。因此,InputStream流只能读取一次。

解决

  1. 将数据流,转成byte数组流,实现数据可重复读取
  2. 可重复读取原因:因为将数据byte数组形式存储在内存中,且ByteArrayInputStream内部源码实现了重复读取byte数组中的数据
    • 即:使用reset()方法,将数组读取idx重置为数组起始位置,然后再次读取还是从数组idx=0位置重新读取
public static void testReadAgain(InputStream in) throws IOException {
    // 将InputStream流读取到ByteArrayInputStream中
    byte[] origin = read(in);
    ByteArrayInputStream byteIn = new ByteArrayInputStream(origin);

    // 通过ByteArrayInputStream流读取数据
    byte[] read1 = read(byteIn);
    String s1 = new String(read1);
    log.info("第一次通过ByteArrayInputStream流读取数据为:{}", s1);

    // 重置流,让流可再次读
    byteIn.reset();

    byte[] read2 = read(byteIn);
    String s2 = new String(read2);
    log.info("第二次通过ByteArrayInputStream流读取数据为:{}", s2);
}
  1. 打印结果
    在这里插入图片描述

总结

  1. InputStream流是否能够重复读取数据,不是由InputStream决定,而是它的实现类决定
  2. 比如:FileInputStream实现了InputStream
    • FileInputStream不能重复读取,是因为在处理文件读取时,需要不停的将文件读取的指针往下移动
    • 当指针移动到文件末尾时,文件读取完成。那么下次读取时,指针无法再往下移动,导致无法重新读取数据。
  3. 比如:ByteArrayInputStream 实现InputStream
    • ByteArrayInputStream可重复读,是因为其内部存储数据是使用byte数组
    • Java中数组长度不可变,且从0开始,那么当需要重复读取时,只需要从0再次读取一遍数组即可
  4. 比如:自己写一个类,实现InputStream接口
    • 自己实现的逻辑里,可以将数据写入到一个临时文件
    • 然后,从文件中将数据读取出来
    • 如果需要重复读取数据,只需要再次读取该文件即可
    • 这样,也实现了InputStream流数据的可重复读取
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值