认知IO流之 — InputStream

简介: InputStream 是一个抽象类,这个抽象类是代表所有字节流输入的父类,应用程序需要定义一个InputStream 的子类,该子类需要提供一个返回下一个输入字节的方法。

InputStream 结构概述

InputStream 是一个抽象类,这个抽象类是代表所有字节流输入的父类,应用程序需要定义一个InputStream 的子类,该子类需要提供一个返回下一个输入字节的方法。

下面是 InputStream 的继承体系:

0.jpg


下面是针对 InputStream 的子类做的图表,从图表中可以对 InputStream 的子类有一个大致的了解

类和功能 构造器参数解释
FileInputStream 用于从文件系统的文件中读取字节。 字符串,表示文件名,文件或 FileDescriptor 对象
FilterInputStream 包含一些其他的输入流,并将其作为基本的数据源,提供数据转换和其他功能 InputStream 类型,包含其任意子类
ObjectInputStream 是将对象的原始数据序列化的输入流 一个可以接收InputStream 类型的构造函数,一个包级私有的无参构造函数
PipedInputStream 管道输入流提供写入管道输出流的任何数据字节,实现管道化的概念 PipedOutputStream管道输出流,也可控制管道容量的大小
SequenceInputStream 将两个或者多个InputStream 转换成单一 InputStream 两个InputStream 对象或一个容纳 InputStream 对象的容器 Enumeration
ByteArrayInputStream 允许内存的缓冲区当作 InputStream 使用 缓冲区,从缓冲区取出字节

InputStream 特性

InputStream 中有一个常量 MAX_SKIP_BUFFER_SIZE,它用来确定最大能够跳过的字节缓冲,主要用于 skip() 方法

privatestaticfinalint MAX_SKIP_BUFFER_SIZE = 2048;

read 方法

作为一个抽象类,InputStream 必须至少有一个抽象方法才可以,这个唯一的抽象方法就是 read()方法

public abstract int read() throws IOException;

read() 方法表示从输入流读取下一个字节的数据,byte字节的值作为 int 返回,其范围在0 - 255 之间。如果到达流的末尾而没有可用的字节的话,则返回 -1, 一般用 -1 来判断字节流是否到了末尾。此方法会被锁住直到有输入数据的时候,这种 IO 流也叫做 BIO阻塞IO,它的效率比较低。子类必须提供此方法的实现。

另外一个同名方法也是 read() 方法,不过这个方法不是抽象方法

public int read(byte b[]) throws IOException {

return read(b, 0, b.length);
}

从输入流中读取一定数量的字节并把它们存储在缓冲数组中。实际读取的字节数以整数形式返回。如果参数 b 的长度是0 ,就不会读取字节并且返回 0;这个方法会尝试读取至少一个字节并存储在b数组中。第一个读取并存储的字节是 b[0],下一个是 b[1],以此类推。读取的字节最多等于 b数组的长度。

这个方法会调用 read(b, 0, b.length) 方法,来看一下此方法的定义

public int read(byte b[], int off, int len) throws IOException {
if (b == null) {
thrownew NullPointerException();
} elseif (off < 0 || len < 0 || len > b.length - off) {
thrownew IndexOutOfBoundsException();
} elseif (len == 0) {
return0;
}
int c = read();
if (c == -1) {
return -1;
}
b[off] = (byte)c;
int i = 1;
try {
for (; i < len ; i++) {
c = read();
if (c == -1) {
break;
}
b[off + i] = (byte)c;
}
} catch (IOException ee) {
}
return i;
}

如果没有可读取的数组,直接抛出空指针异常,如果起始读取位置小于0,或者读取长度小于0,或者需要读取的长度要比实际的长度大,抛出数组越界异常,若读取的长度为0,那么就不会读取任何字节。上面代码调用的 read() 无参数的方法交给子类去实现,如果子类读取到了 -1 ,那么就直接返回 -1。

skip 方法

public long skip(long n) throws IOException {
long remaining = n;
int nr;
if (n <= 0) {
return0;
}
int size = (int)Math.min(MAX_SKIP_BUFFER_SIZE, remaining);
byte[] skipBuffer = newbyte[size];
while (remaining > 0) {
nr = read(skipBuffer, 0, (int)Math.min(size, remaining));
if (nr < 0) {
break;
}
remaining -= nr;
}
return n - remaining;
}

跳过并丢弃此输入流中的字节数据。由于各种原因,skip 方法最终可能会跳过一些较小的字节数,可能是0。这可能是由许多条件中的任何一个引起的;只有一种可能性就是在跳过 n 个字节之前到达末尾。此方法会返回跳过的实际字节数。如果 n 是负数,skip 方法总是返回 0,并且不跳过任何字节。

available 方法

public int available() throws IOException {
return0;
}

返回下一个方法调用能不受阻塞地从此读取(或者跳过)的估计字节数。注意,InputStream 的某些实现将返回流中的总字节数,但是许多实现则不会。

如果输入流通过调用 close() 方法关闭后,此方法的子类实现还会抛出 IOException。InputStream 类的 available 方法总是返回 0 。

close 方法

public void close() throws IOException {}

关闭这个输入流并且释放流分配的系统资源。InputStream 的 close 方法不做任何操作。

mark 方法

public synchronized void mark(int readlimit) {}

用于标记输入流当前的位置。随后对 reset 方法的调用会在最后标记的位置处重新定位此流的位置以便后续重新读取相同的字节。

readlimit 参数会告诉输入流允许在标记位置失效之前读取多个字节。

mark 方法的一般约定是,如果方法 markSupported 返回 true,那么在调用mark方法后,流会以某种方式记录所有读取的字节。当调用reset方法后,能够再次提供同样的字节。但是,在调用reset之前,流不会记录readlimit以外的字节。在已经关闭的流上调用mark方法对流没有影响

InputStream 的 mark 方法不会做任何事情。

reset 方法

public synchronized void reset() throws IOException {
thrownew IOException("mark/reset not supported");
}

将此流重新定位到上次在此输入流上调用 mark 方法的位置。

reset 的一般规定是如果 markSupported 方法返回 true,则

自从流被创建后如果没有调用 mark 方法,或者 mark方法从最后一次调用后从流中读取的字节数量要大于最后一次调用时 mark 的参数的话,可能抛出 IOException。

如果没有抛出 IOException 的话,这时流会重置为一种状态,这时从最近一次调用 mark 以来所读取的所有字节将被提供给 read 方法的后续调用者。

如果 markSupported 返回 false,则这个 reset 调用可能抛出 IOException,如果没有抛出 IOException 的话,则将流重置为固定状态,该状态取决于输入流的特定类型及其创建方式。

markSupported 方法

public boolean markSupported() {
returnfalse;
}

markSupported 方法就是一个判断是否支持 mark 和 reset 方法的标示。返回 true 表示支持,默认是 false。

            </div>
目录
相关文章
|
安全 Java Maven
最小化 Java 镜像的常用技巧
随着容器技术的普及,越来越多的应用被容器化。人们使用容器的频率越来越高,但常常忽略一个基本但又非常重要的问题 - 容器镜像的体积。本文将介绍精简容器镜像的必要性并以基于 spring boot 的 java 应用为例描述最小化容器镜像的常用技巧。
4782 0
|
安全 Shell 网络安全
【服务器】Xshell与Xftp软件的使用指南
【服务器】Xshell与Xftp软件的使用指南
1499 0
|
7月前
|
JavaScript 数据可视化 前端开发
基于 Vue 与 D3 的可拖拽拓扑图技术方案及应用案例解析
本文介绍了基于Vue和D3实现可拖拽拓扑图的技术方案与应用实例。通过Vue构建用户界面和交互逻辑,结合D3强大的数据可视化能力,实现了力导向布局、节点拖拽、交互事件等功能。文章详细讲解了数据模型设计、拖拽功能实现、组件封装及高级扩展(如节点类型定制、连接样式优化等),并提供了性能优化方案以应对大数据量场景。最终,展示了基础网络拓扑、实时更新拓扑等应用实例,为开发者提供了一套完整的实现思路和实践经验。
926 77
|
10月前
|
机器学习/深度学习 人工智能 算法
基于蓝牙室内定位技术的院内智能导航系统
本文介绍了一款基于蓝牙室内定位技术的院内智能导航系统。该系统通过高精度定位与智能路径规划,极大提升了患者就医体验与医院运营效率。如需获取智慧医院院内导航系统技术文档可前往文章最下方获取,如有项目合作及技术交流欢迎私信我们哦~
377 1
|
开发者 UED Ruby
Ruby中的异常处理之谜:如何用异常与rescue让你的代码坚不可摧?
【8月更文挑战第31天】在软件开发中,错误处理对应用稳定性至关重要。作为动态、面向对象的语言,Ruby提供了丰富的错误处理机制,如异常与rescue。本文通过示例代码介绍了Ruby中的异常类型、异常链及rescue与else的使用,展示了如何优雅地处理各种错误情况,增强了程序的健壮性和用户体验。使用这些机制,开发者能更精准地识别并解决运行时问题,提升应用质量。随着Ruby生态的发展,错误处理的重要性将愈发凸显。
266 1
|
负载均衡 监控 Kubernetes
Service Mesh 是一种用于处理服务间通信的基础设施层,它通常与微服务架构一起使用,以提供诸如服务发现、负载均衡、熔断、监控、追踪和安全性等功能。
Service Mesh 是一种用于处理服务间通信的基础设施层,它通常与微服务架构一起使用,以提供诸如服务发现、负载均衡、熔断、监控、追踪和安全性等功能。
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的网上商城系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的网上商城系统附带文章源码部署视频讲解等
203 1
|
监控 安全 网络协议
什么是udp攻击,为什么udp攻击这难防御
UDP是无连接的传输协议,常用于需要速度但不要求可靠性的场景,如DNS查询、流媒体等。UDP Flood是DDoS攻击的一种,通过大量伪造的UDP报文消耗目标带宽,可能导致网络瘫痪。防御UDP Flood包括限流、静态指纹过滤和动态指纹学习。应用加速技术提供抗DDoS、CC防护、环境安全检测等功能,通过隐藏真实IP、加密传输和智能调度增强安全性。
|
前端开发
vue3 【提效】使用 CSS 框架 UnoCSS 实用教程
vue3 【提效】使用 CSS 框架 UnoCSS 实用教程
976 1
|
前端开发
招聘求职系统|基于Springboot+Vue+Nodejs实现求职招聘系统(三)
招聘求职系统|基于Springboot+Vue+Nodejs实现求职招聘系统
284 0
招聘求职系统|基于Springboot+Vue+Nodejs实现求职招聘系统(三)