基本说明
在Java API中,可以从其中读入一个字节序列的对象称作输入流,而可以向其中写入一个字节序列的对象称作输出流。这些字节序列的来源地和目的地可以是文件,而且通常都是文件,但是也可以是网络连接,甚至是内存块。抽象类InputStream和OutputStream构成了输入/输出(I/O)类层次结构的基础。而Reader和Writer又可以很轻松的基于Unicode文本进行操作。
InputStream和OutputStream
在学习输入输出流之前,我们有必要来看一下InputStream和OutputStream的类图
InputStream内容如下
OutputStream内容如下
InputStream和OutputStream方法的一些说明
在InputStream里面最重要的就是read方法,该方法可以读入字节。而在OutputStream里面最重要的就是write方法,该方法可以写出字节。
我们知道InputStream和OutputStream都实现了AutoClosed接口,所以我们在使用这2个类的时候可以使用try-with-Resource让其自动关闭。如果不使用try-with-Resource,那么我们在使用完输入/输出流之后也应该调用其close方法来释放资源。
对于关闭输出流,我们还需要注意一些内容:关闭一个输出流的同时还会冲刷用于该输出流的缓冲区:所有被临时置于缓冲区中,以便用更大的包的形式传递的字节在关闭输出流时都将被送出。特别是,如果不关闭文件,那么写出字节的最后一个包可能永远也得不到传递。当然,我们还可以用flush方法来人为地冲刷这些输出。
需要注意的一点是read和write方法在执行时都会被阻塞,直至字节确实被读入或者写出。我们可以使用available方法来判断是否还可以进行读取。该方法会返回在不阻塞的情况下可获取的字节数
java中的输入/输出流家族
在java中拥有应该流家族,包含各种输入/输出流类型,数量超过60个,具体内容如下
让我们把输入/输出流家族中的成员按照它们的使用方法来进行划分,这样就形成了处理字节和字符的两个单独的层次结构。正如所见,InputStream和OutputStream类可以读写单个字节或字节数组,这些类构成了第一张图所示的层次结构的基础。要想读写字符串和数字,就需要功能更强大的子类,例如,DataInputStream和DataOutputStream可以以二进制格式读写所有的基本Java类型。最后,还包含了多个很有用的输入/输出流,例如,ZipInputStream和ZipOutputStream可以以我们常见的ZIP压缩格式读写文件。
另一方面,对于Unicode文本,可以使用抽象类Reader和Writer的子类(第二张图)。Reader和Writer类的基本方法与InputStream和OutputStream中的方法类似。
- read方法将返回一个Unicode码元(一个在0~65535之间的整数),或者在碰到文件结尾时返回-1。
- write方法在被调用时,需要传递一个Unicode码元
Reader和Writer
二者的类图如下
Reader内容
Writer内容
Reader和Writer类的基本方法与InputStream和OutputStream中的方法类似,就不细说了,大家可以参考源代码上面的注释
总结
InputStream和OutputStream算是所有二进制输入/输出的父类,而Reader和Write算是所有字符输入/输出的父类。它们的子类提供了各种形式的输入/输出方法,我们使用它们可以很轻松的完成输入/输出操作。