第15章-输入/输出 --- 理解Java的IO流
(一)理解Java的IO流
JAVA的IO流是实现输入/输出的基础,它可以方便地实现数据的输入/输出操作,在Java中把不同的输入/输出(键盘、文件、网络连接等)抽象表述为"流"(Stream),通过流的方式允许Java程序使用相同的方式来访问不同的输入/输出源。
Stream是从起源(source)到接收(sink)的有序数据
(二)流的分类
1.输入流和输出流
按照流的流向来分,可以分为输入流和输出流:
a. 输入流:只能从中读取数据,而不能向其写入数据。
b. 输出流:只能向其写入数据,而不能从中读取数据。
此处的输入、输出涉及一个方向问题,如下图所示的数据流向:数据从内存到硬盘,通常称为输出流--也就是说,这里的输入、输出都是从程序运行所在内存的角度来划分的。
对于下面所示的数据流向,数据从服务器通过网络流向客户端,在这种情况下,Server端的内存负责将数据输出到网络里,因此Server端的程序使用输出流;Client端的内存负责从网络里读取数据,因此Client端的程序应该使用输入流。
2.字节流和字符流
字节流和字符流的用法几乎完全一样,区别在于字节流和字符流所操作的数据单元不同--字节流操作的数据单元是8位字节,而字符流操作的数据单元是16位的字符
字节流主要有InputStream和OutputStream作为基类,而字符流则组要由Reader和Writer作为基类。
3.节点流和处理流
按照流的角色来分,可以分为节点流和处理流:
可以从/从一个特定的IO设备(如磁盘、网络)读/写数据的流,称为节点流,节点流也被称为低级流(Low Level Stream)。
下图显示了节点流示意图:
从上图可以看出,当使用节点流进行输入/输出时,程序直接连接到实际的数据源,和时间的输入/输出节点连接。
处理流则用于对一个已存在的流进行连接或封装,通过封装后的流来实现数据读/写功能,处理流也被称为高级流。
下图显示了处理流示意图:
从上图可以看出,当使用处理流进行输入/输出时,程序并不会直接连接到实际的数据源,没有和实际的输入/输出节点连接。使用处理流的一个明显好处是,只要使用相同的处理流,程序就可以采用完全相同的输入/输出代码来访问不同的数据源,随着处理流所包装节点流的变化,程序实际所访问的数据源也相应的发生变化。
(三)流的概念模型
Java的IO流共涉及40多个类,这些类看上去很凌乱,但实际上非常规则,而且彼此之间存在非常紧密的联系。Java的IO流的40多个类都是从如下4个抽象类派生的:
(1)InputStream/Reader:所有输入流的基类,前者是字节输入流,后者是字符输入流。
(2)OutputStream/Writer:所有输出流的基类,前者是字节输出流,后者是字符输出流。
对于InputStream和Reader而言,它们把输入设备抽象成一个"水管",这个水管里的每一个"水滴"一次排序:
如下图:
从上图可以看出,字节流和字符流的处理方式其实非常相似,只是它们处理的输入/输出单位不同而已。输入流使用隐式的记录指针来表示当前正准备从哪个"水滴"开始读取,每当程序从InputStream或Reader里取出一个或多个"水滴"后,记录指针自动向后移动;除此之外,InputStream和Reader里都提供了一些方法来控制记录指针的移动。
对于OutputStream和Writer而言,它们同样把输出设备抽象成一个"水管",只是这个水管里没有任何水滴,如下图:
如上图,当执行输出时,程序相当于依次把"水滴"放入到输出流的水管中,输出流同样采用隐式的记录指针来标识当前水滴即将放入的位置,每当程序向OutputStream或Writer里输出一个或多个水滴后,记录指针自动向后移动。
上面两幅图显示了Java IO流的基本概念模型,除此之外,Java的处理流模型则体现了Java输入/输出流设计的灵活性。
处理流的功能主要体现在以下两个方面:
(1)性能的提高:主要以增加缓冲的方式来提供输入/输出的效率。
(2)操作的便捷:处理流可能提供了一系列便捷的方法来一次输入/输出大批量的内容,而不是输入/输出一个或多个“水滴”。