当前位置: 首页 > article >正文

InputStream为什么不能被重复读取?为啥只能被读取一次?

问题

熟悉Java的人可能都知道,Java中的Inputstream是不能重复读取的。
但是有没有想过,InputStream为什么不能重复读呢? 其实要回答“为什么”这个问题很简单,就是人家接口就是这么设计的,不能重复读。
也就是说获取到一个inputstream后,可能要多次利用它进行read的操作。由于流读过一次就不能再读了,而InputStream对象本身不能复制,而且它也没有实现Cloneable接口。

分析

关于InputStream为什么不能重复读取,网上也各有说法:

说法一
“InputStream就类比成一个杯子,杯子里的水就像InputStream里的数据,你把杯子里的水拿出来了,杯子的水就没有了,InputStream也是同样的道理。”
比喻的非常好,让我们从直观上认识了InputStream为什么不能重复被读。

说法二
“在InputStream读取的时候,会有一个pos指针,他指示每次读取之后下一次要读取的起始位置,当读到最后一个字符的时候,pos指针不会重置。”
说的也有道理,就是说InputStream的读取是单向的。但是并不是所有的InputStream实现类都是这样的实现方式。

剖析

Java 的List内部是使用数组实现的,遍历的时候也有一个pos指针。但是没有说List遍历一个第二次遍历就没有了。第二次遍历是创建新的Iterator,所以pos也回到了数组起始位置。对于某些InputStream当然可以也这么做。例如:ByteArrayInputStream
ByteArrayInputStream就是将一个Java的byte数组保存到对象里,然后读取的时候遍历该byte数组。

Java代码   收藏代码
public ByteArrayInputStream(byte buf[]) {  
        this.buf = buf;  
        this.pos = 0;  
        this.count = buf.length;  
}  
  
public synchronized int read() {  
        return (pos < count) ? (buf[pos++] & 0xff) : -1;  
}  

就ByteArrayInputStream而言,要实现重复读取是很简单的,但是为什么没有。我想是为了遵循InputStream的统一标准。
在InputStream的read方法的注释上明确说明:
Java代码 收藏代码

/** 
     * Reads the next byte of data from the input stream. The value byte is 
     * returned as an <code>int</code> in the range <code>0</code> to 
     * <code>255</code>. If no byte is available because the end of the stream 
     * has been reached, the value <code>-1</code> is returned. This method 
     * blocks until input data is available, the end of the stream is detected, 
     * or an exception is thrown. 
     * 
     * <p> A subclass must provide an implementation of this method. 
     * 
     * @return     the next byte of data, or <code>-1</code> if the end of the 
     *             stream is reached. 
     * @exception  IOException  if an I/O error occurs. 
     */  
    public abstract int read() throws IOException;  

当流到达末尾后,返回-1.

总结

其实像FileInputStream这样的文件流,要实现重复使用可能也并不是很难,利用缓存什么的应该能做到(大文件读取就悲剧了,呵呵呵)。
但是InputStream顾名思义就是一个单向的字节流,跟水流一样,要想再次使用就自己再去源头取一下。
InputStream其实不像杯子,更像是一根水管,要想喝水了,就在把水管架在水源与杯子之间,让水流到杯子里(注意:这个动作完成了之后水管里面就没有水了)。
这样看来,InputStream其实是一个数据通道,只负责数据的流通,并不负责数据的处理和存储等其他工作范畴。
前面讲过,其实有的InputStream实现类是可以实现数据的处理工作的。但是没有这么做,这就是规范和标准的重要性。


http://www.kler.cn/a/325954.html

相关文章:

  • WPF的基础控件详解
  • 《Spring 基础之 IoC 与 DI 入门指南》
  • 【深度学习】使用硬件加速模型训练速度
  • Flutter网络通信-封装Dio
  • OMV7 树莓派 tf卡安装
  • MySQL中将一个字符串字段按层级树状展开
  • 探索 Android DataBinding:实现数据与视图的完美融合
  • 腾讯邮箱上传附件卡、慢、无法上传,下载慢问题处理
  • Harmony 获取定位位置的方式
  • 休眠唤醒不了?你的4G模组不是装睡,而是少了一条指令…
  • Spring Mvc 基础源码分析
  • OceanBase 关于一号表笔记与ERROR 1060(42S21)问题
  • 表驱法优化代码
  • 入职2年的程序员,被劝退了!年纪大了,感觉好绝望!
  • Studying-图论包含的算法总结
  • [Python学习日记-31] Python 中的函数
  • Java开发:文件上传和下载
  • PCL 移动立方体重建(HOPPE)
  • STM32引脚PB3、PB4、PA15作为输入输出的特殊配置
  • mysql代理服务器
  • 自然语言处理实战项目
  • MinIO使用客户端进行桶和对象的管理
  • OpenCV视频I/O(1)视频采集类VideoCapture介绍
  • Mybatis-Mapper接口方式
  • SpringBoot依赖之Microsoft SQL Server Driver
  • 谈谈Redisson分布式锁的底层实现原理