InputStream(一)

首先了解对流的定义:
流分两种,输入流和输出流:
输入流:可以从其中读入一个字节序列的对象称作输入流。
输出流:可以向其中写入一个字节序列的对象称作输出流。

字节序列的来源和目的地:文件、网络连接、甚至是内存块。

其次从结构图中看整个IO流的一个大致的脉络:

这里写图片描述

从结构图中可以看出整个IO流分为两大块,字节流和字符流。

原因:面向字节的流不便于处理以Unicode形式存储的信息(Unicode中每个字符都使用了多个字节来表示),所有从抽象类Reader和Writer中继承出来了一个专门处理Unicode字符的单独的类层次结构。这些类拥有的读入和写出操作都是基于两个字节的Unicode码元的,而不是基於单字节的字符。

而由于字符流是建立在字节流之上的,所以对于总体来说,InputStream和OutputStream构成了输入/输出(I/O)类层次结构的基础。

所以之后得从InputStream的API中去了解是怎么实现工作原理的,在这里说一下,jdk版本为1.7:

InputStream API:

这里写图片描述

在这里可以看出InputStream这个抽象类实现了Closeable这个接口。

追踪到对原始的接口AutoCloseable接口里去会发现这个接口中只有一个close()方法:

这里写图片描述

在这里我们预想的肯定是InputStream这个抽象类中实现了AutoCloseable接口中的close()方法,那么回过头来看InputStream这个抽象类:

这里写图片描述

在InputStream这个抽象类中,我们只看到了这个模板方法,并没有对AutoCloseable接口里的close()方法做相应的处理,由此可见,close()方法必定由InputStream的子类去实现。

想到这,我们可以从结构图中找一个InputStream中找一个子类来大致看一下close()是怎么实现的,在这里我找的是FileInputStream,下面来看一下对close()的处理:

这里写图片描述
这里写图片描述

在这里不细说这段代码处理的流程,因为之后补充的时候有可能会提到,到时候细说,大致说一下close()方法的作用:

每当完成对流的读写时,应当通过close()方法来关闭,这个调用会释放十分有限的操作系统资源,同时还会冲刷用于该输入输出流的缓存区,所有被置于缓存区中,以便于用更大的包的形式,传递的字符,在关闭输入/输出流时都将被送出。
如果不关闭文件,那么写出字节的最后一个包可能永远也得不到传递。

手动:可以用flush()方法来人为的冲刷这些输出。

现在我们回到InputStream这个抽象类中,来看看里面的方法到底有什么作用。

读写字节:

这里写图片描述

从对这个方法的注释中,我们可以了解到read()这个抽象方法是从输入流中读取下一个字节的数据。字节的值作为int范围在0到返回255,如果没有可以的字节(遇到输入源结尾时)返回-1.

这个方法块直到输入数据是可用的,检测到流的结束,或者抛出异常。
该方法的一个子类必须提供一个实现。

读入一个字节数组:
这里写图片描述

在这个方法中,传入了一个byte类型的字节数组,之后再跳转到有三个参数的read()中,我们在来看有三个参数的read()方法。

这里写图片描述
这里写图片描述

在这段代码中,我们首先来看看三个参数的作用:
byte[] b:要被处理的一个字节序列
int off :第一个读入字节应该被放置在b中的偏移量,默认是0
int len : 读入字节的最大数量

在方法中新建了int类型的变量i,用来记录读入的字节数,并且在方法的最后返回。

所以综上所述:

这里写图片描述

这个方法是读入一个数组,并且返回实际读入的字节数,或者在碰到流的结尾时返回-1(read()方法中实现),但是这个方法最多读入b.length个字节。

在输入流中跳过n个字节:

这里写图片描述

首先理解一下这段代码做了什么:

首先确定了读取数组的大小,用Math.min这个方法来比较两个参数的大小,并选取小的那个值作为数组的大小,这里解释一下两个参数:

MAX_SKIP_BUFFER_SIZE:用于确定最大缓存区大小,这里确定值为2048
remaining:传入的参数的字节数大小

这里可以理解为当传入跳过的字节数大于最大缓存区大小时截取传入跳过的字节数,截取的大小为最大缓存区大小。

之后用读取数组的方式读取,最后返回实际跳过的字节数(如果碰到流的结尾,则可能小于n)。

在不阻塞的情况下可获取的字节数(阻塞意味着当前线程将失去它对资源的占用)

这里写图片描述

从对这个方法的注释上我们可以知道,这个方法是被用来获取不阻塞情况下读入的字节数,并且这个方法是应该被子类所覆盖的。

标记输入流的位置:

这里写图片描述

从对API的注释解释中可以知道这个方法的作用:
在输入流的当前位置打了一个标记(并非所有的流都支持这个特性),如果从输入流中已经读入的字节对于readlimit,则这个流允许忽略这个标记。

重置读入流:

这里写图片描述

返回到最后一个标记,随后对read的调用将重新读入这些字节。如果当前没有任何标记,则这个流不能被重置,同样的这个类需要子类去实现。

判断流是否允许打标记

这里写图片描述

如果这个流支持打标记,则返回true,不过不支持,返回false。

总结:应用系统的程序员还是很少使用原来的read()和writer()方法,因为大家感兴趣的数据可能包含数字、字符串和对象,而不是原生字节。
所以Java提供了众多从基本的InputStream和OutputStream导出的类,来处理以常用格式表示的数据。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章