首先,熟悉Java的人可能都知道,Java中的Inputstream是不能重复读取的。
但是有没有想过,InputStream为什么不能重复读呢?
其实要回答“为什么”这个问题很简单,就是人家接口就是这么设计的,不能重复读。
所以今天要讨论的问题更像是:Java的InputStream为什么要设计为不能重复读?
关于InputStream为什么不能重复读取,网上也各有说法:
有的同学说:
“InputStream就类比成一个杯子,杯子里的水就像InputStream里的数据,你把杯子里的水拿出来了,杯子的水就没有了,InputStream也是同样的道理。”
比喻的非常好,让我们从直观上认识了InputStream为什么不能重复被读。
也有的同学从更深的代码角度去分析:
“在InputStream读取的时候,会有一个pos指针,他指示每次读取之后下一次要读取的起始位置,当读到最后一个字符的时候,pos指针不会重置。”
说的也有道理,就是说InputStream的读取是单向的。但是并不是所有的InputStream实现类都是这样的实现方式。
//BufferedInputStream代码片段:
public synchronized int read() throws IOException {
if (pos >= count) {
fill();
if (pos >= count)
return -1;
}
return getBufIfOpen()[pos++] & 0xff;
}
//FileInputStream代码片段:
public native int read() throws IOException;
我们知道:
Java 的List内部是使用数组实现的,遍历的时候也有一个pos指针。但是没有说List遍历一个第二次遍历就没有了。第二次遍历是创建新的Iterator,所以pos也回到了数组起始位置。对于某些InputStream当然可以也这么做。例如:ByteArrayInputStream
ByteArrayInputStream就是将一个Java的byte数组保存到对象里,然后读取的时候遍历该byte数组。
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方法的注释上明确说明:
/**
* 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实现类是可以实现数据的处理工作的。但是没有这么做,这就是规范和标准的重要性。
分享到:
相关推荐
我们可以创建一个自定义的`HttpServletRequestWrapper`子类,重写`getInputStream()`方法,使其返回一个可以重复读取的`InputStream`。 以下是一个简单的自定义`HttpServletRequestWrapper`示例: ```java import ...
java * 构建可重复读取inputStream的requestjava * 构建可重复读取inputStream的requestjava * 构建可重复读取inputStream的requestjava * 构建可重复读取inputStream的requestjava * 构建可重复读取inputStream的...
这篇文章将详细介绍为什么 SpringMVC 中请求的 body 不支持多次读取,并提供解决方案。 在 Springboot 的项目中,使用 Servlet 的 Filter 来实现方法签名时,发现请求的 body 不支持多次读取。这是因为在 Servlet ...
通过这种方式,我们可以在不依赖外部文件或网络连接的情况下,多次读取同一份数据。 在上述的MyCat配置文件读取示例中,原始代码每次调用 `loadRoot()` 方法都会打开并读取 `mycat.dtd` 和 `mycat.xml` 文件。这...
这个例子展示了如何使用SXSSFWorkbook来读取Excel文件,只保留100行数据在内存中,其他超出的行会被自动写入磁盘。处理完数据后,记得调用`dispose()`方法释放内存。 总结来说,解决Java读取Excel内存溢出问题,...
可以使用AsyncTask或其他异步处理机制,如使用Glide、Picasso等第三方库,它们能更高效、智能地管理内存和加载过程,同时提供缓存机制,减少重复网络请求。 此外,处理网络图片时还需考虑异常处理,例如网络中断、...
这是因为InputStream只能读取一次,如果我们想要重复读取流中的数据,就需要自定义一个HttpServletRequestWrapper。 通过继承HttpServletRequestWrapper,我们可以将请求体中的流copy一份,覆写getInputStream()和...
在处理这类问题时,开发者应确保一次性处理完所有数据,或者先将数据复制到可重复读取的数据结构中。同时,深入理解Java I/O流的原理,特别是`read()`、`mark()`和`reset()`方法,对于优化和调试Web应用的输入处理...
通过这样的工具类,开发者可以方便地加载和获取配置文件中的属性值,避免重复编写相同的代码。下面我们将详细探讨`properties`文件、如何创建工具类以及如何使用此类进行文件读取。 1. **什么是.properties文件** ...
在Java编程中,`InputStream`是处理字节流的基础类,广泛用于读取各种输入数据,如文件、网络连接等。然而,有时我们可能需要对输入流进行缓冲或重新读取,以实现某些高级功能,比如数据缓存、断点续传等。`restream...
这样的工具类能够使代码更具有可维护性和复用性,避免在多个地方重复处理Properties文件。 下面将详细解释Properties类的核心概念和如何创建一个用于读取Properties信息的工具类: 1. **Properties类介绍**: - ...
上面的实例代码中,使用了 RedisTemplate 来缓存读取的数据,以避免重复读取和中途异常退出。 知识点四:使用自动化工具和脚本来实现批量下载 在批量下载远程数据时,可以使用自动化工具和脚本来实现批量下载。...
如果需要重复读取流中同一段内容,则需要使用流类中的 mark 方法进行标记,然后才能重复读取。 本文档对 Java 中的输入输出流和文件读写进行了详细的介绍,涵盖了 I/O 类的体系结构、字节流和字符流、InputStream ...
Excel POI读取封装(文件+示范代码) package org.excel.service; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; import java....
System.err.println("不能读取属性文件. " + "请确保db.properties在CLASSPATH指定的路径中"); } finally { if (is != null) { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } }...
Reader 用于读取字符流(char 或 String),InputStream 用于读取字节流(byte 数组)。 8. HashMap 中是否任何对象都可以作为 key? 可以,但是要 key 对象必须是不可变的对象,不然在 Entry 被插入 Map 中后,再...
都是抽象类,Reader用于读取字符流(char或String),InputStream用于读取字节流(byte数组)。 8. HashMap中是否任何对象都可以做为key,用户自定义对象做为key有没有什么要求? 可以,但是要key对象必须是不可变...
为什么使用 application.properity 文件? 使用 application.properity 文件有很多优点,例如: * decoupling:application.properity 文件与应用程序的业务逻辑相分离,易于维护和修改。 * flexiblity:...
Reader和InputStream都是抽象类,Reader用于读取字符流(char或String),InputStream用于读取字节流(byte数组)。 8. HashMap中是否任何对象都可以作为key,用户自定义对象作为key有什么要求? 答案是,可以,...
标题中的“可重复使用文件保存”可能指的是在编程中如何设计和实现一种文件保存机制,使得文件内容可以被多次读取和写入,而不会丢失数据或者产生冲突。这种机制通常涉及到文件操作、数据持久化以及多线程安全等方面...