程序员潇然 发表于 2022-8-16 11:27:39

JavaIO之InputStream OutputStream简介 方法列表说明(六)

InputStream 和 OutputStream 对于字节流的输入和输出
是作为协议的存在
所以有必要了解下这两个类提供出来的基本约定
这两个类是抽象类,而且基本上没什么实现,都是依赖于子类具体的去实现
但是他是对于其子类 协议纲领一般的存在
了解清楚每一个方法含义,对于后续具体的子类将会有非常大的帮助

### 基本含义

| 类         | 说明                                 |
| ------------ | ------------------------------------ |
| InputStream| 所有字节输入流的 超类 他是一个抽象类 |
| OutputStream | 所有字节输出流的 超类 他是一个抽象类 |


### 方法列表

!(data/attachment/forum/202208/16/111844vkvdapqumzvdbkwg.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

InputStream包含了读取方法以及辅助方法

OutputStream包含了写入方法以及辅助方法


### 方法对照

| 读相关                                                                     | 写相关                                                   |
| ---------------------------------------------------------------------------- | ---------------------------------------------------------- |
| read()<br />read(byte[])<br />read(byte[], int, int)                         | write(byte[])<br />write(byte[], int, int)<br />write(int) |
| close                                                                        | close                                                      |
|                                                                              | flush()                                                    |
| available()<br />mark(int)<br />markSupported()<br />reset()<br />skip(long) |                                                            |


### 方法详解

#### read

`read()`从输入流中读取数据的下一个字节。返回 0 到 255 范围内的 int 字节值
如果因为已经到达流末尾而没有可用的字节,则返回值 -1


方法将会一直阻塞,直到数据可用,检测到流的末尾或者抛出异常

无参数的 `read()` 是抽象方法,由实现类提供实现
三个 `read()`方法实际上根本方法都是 `read()`方法
其他两个方法为拓展功能,逻辑便捷方法

无参数的 `read()`返回的数据为读取到的字节值
而有参数的则是读取到字节数组中,所以返回值为读取到的个数


read方法关键点
要么就是直接返回读取的字节
要么就是将读取到的字节放入字节数组中,字节数组是你传递进去的

!(data/attachment/forum/202208/16/112047bi0ofihtbzdtptft.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

#### write

`write(int b)`
将指定的字节写入此输出流
write 的常规协定是:向输出流写入一个字节, 要写入的字节是参数 b 的八个低位   b 的 24 个高位将被忽略
说白了就是写入的是byte虽然参数是int

`write(byte[] b)`
将 ` b.length` 个字节从指定的 byte 数组写入此输出流
`write(b) `的常规协定是:应该与调用 `write(b, 0, b.length)` 的效果完全相同


`write(byte[] b,int off,int len)`
将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流
`write(b, off, len)` 的常规协定是:将数组 b 中的某些字节按顺序写入输出流;
元素 `b` 是此操作写入的第一个字节,`b `是此操作写入的最后一个字节


类似 `read`的调用形式 直接写入指定字节的 `write(int b) ` 方法是根本
其他的是拓展功能

!(data/attachment/forum/202208/16/112242oflkldlrtdyds1td.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")

`read()`与 `write(int b)` 是根本的读取一个字节或者写入一个字节的方法
其余形式是针对传入字节数组作为参数,以及指定字节数组的偏移量时的一些拓展功能
一旦传递了字节数组作为参数
read将会读取数据到字节数组
write将会将字节数组的数据写入

#### close

都需要关闭流,所以都有close方法
都是关闭流并释放与此流有关的系统资源
都可能抛出IOException


在InputStream和OutputStream中,两个close方法都是空方法

#### flush

flush的含义为刷新,在写入数据时使用
所以,只有输出流拥有flush方法


之所以需要刷新,是因为有的输出流的写方法实现,可能已经缓冲了以前写入的任何字节
那么,这个方法用于提供能够立即将数据写入到磁盘的功能
不过,只是立即请求操作系统进行处理,而不保证这些字节实际已经写入到物理设备,比如磁盘


#### InputStream独有

`public int available()throws IOException`
返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数
这句话有些绕口,直白的说就是:
在方法调用前,可以获取到这个流中可用的字节数目
假设说有N个字节可以使用,显然你应该很可能读取到N个字节,或者能够跳过N个字节
一次读取或跳过此估计数个字节不会受阻塞


注意:
这个数目是一个预估的数量
实际的读取或者跳过的字节数可能小于这个数


InputStream中的这个方法总是返回0
所以这个方法能否使用依赖于子类的实现

!(data/attachment/forum/202208/16/112434btuukkjxkxpp1kx9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")


`public long skip(long n) throws IOException`
返回的是实际跳过的字节数
在内部创建一个 byte 数组,然后重复将字节读入其中,直到读够 n 个字节或已到达流末尾为止

!(data/attachment/forum/202208/16/112508qzhm70a0e40lsa5s.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")


`reset()`
`mark(int)`
`markSupported()`
三个方法是对于同一个功能点的不同方法,可以解决重复读的问题

`mark(int)`用来在此输入流中做标记,标记当前位置打一个书签
`markSupported() `测试此输入流是否支持 mark 和 reset 方法
`reset() ` 将此流重新定位到最后一次对此输入流调用 mark 方法时的位置   回到书签

看下类中的默认代码可以发现:
默认情况下 `mark`什么都不做 `markSupported`直接返回false
`reset`方法的调用会抛出异常

!(data/attachment/forum/202208/16/112611spahppgiep5pw6f8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "image.png")


mark的参数用于告知输入流在标记位置失效之前允许读取的字节数
标记已关闭的流对其无效
说起来很迷惑,用起来却很简单
比如

```
xxxStream.mark(50);//表明系统至少应该缓冲50以上个数据,以保证可以回来重新读取
xxxStream.read();
.....
xxxStream.read();

xxxStream.reset();//reset之后,读取到的数据将会和刚才调用mark 方法后read的数据是相同的
xxxStream.read();
.....
xxxStream.read();
```



如果方法 markSupported 返回 true,那么输入流总是在调用 mark 之后记录所有读取的字节
并时刻准备在调用方法 reset 时(无论何时),再次提供这些相同的字节
但是,如果在调用 reset 之前可以从流中读取多于 readlimit 的字节,则不需要该流记录任何数据

!(data/attachment/forum/202206/16/141330jha7st9soow8772i.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "common_log.png")
`转载务必注明出处:程序员潇然,疯狂的字节X,https://crazybytex.com/thread-138-1-1.html `
页: [1]
查看完整版本: JavaIO之InputStream OutputStream简介 方法列表说明(六)