按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
通过继承,从 InputStream (输入流)衍生的所有类都拥有名为read()的基本方法,用于读取单个字节或者
字节数组。类似地,从 OutputStream 衍生的所有类都拥有基本方法 write(),用于写入单个字节或者字节数
组。然而,我们通常不会用到这些方法;它们之所以存在,是因为更复杂的类可以利用它们,以便提供一个
更有用的接口。因此,我们很少用单个类创建自己的系统对象。一般情况下,我们都是将多个对象重叠在一
起,提供自己期望的功能。我们之所以感到Java 的流库(Stream Library)异常复杂,正是由于为了创建单
独一个结果流,却需要创建多个对象的缘故。
很有必要按照功能对类进行分类。库的设计者首先决定与输入有关的所有类都从 InputStream 继承,而与输
出有关的所有类都从OutputStream 继承。
10。1。1 InputStream 的类型
InputStream 的作用是标志那些从不同起源地产生输入的类。这些起源地包括(每个都有一个相关的
InputStream子类):
(1) 字节数组
(2) String对象
(3) 文件
(4) “管道”,它的工作原理与现实生活中的管道类似:将一些东西置入一端,它们在另一端出来。 (5) 一
系列其他流,以便我们将其统一收集到单独一个流内。
(6) 其他起源地,如 Internet 连接等(将在本书后面的部分讲述)。
除此以外,FilterInputStream 也属于 InputStream 的一种类型,用它可为“破坏器”类提供一个基础类,
以便将属性或者有用的接口同输入流连接到一起。这将在以后讨论。
表 10。1 InputStream 的类型
类 功能 构建器参数/如何使用
ByteArrayInputStream 允许内存中的一个缓冲区作为 InputStream使用 从中提取字节的缓冲区/作为一个
数据源使用。通过将其同一个 FilterInputStream 对象连接,可提供一个有用的接口
285
…………………………………………………………Page 287……………………………………………………………
StringBufferInputStream 将一个 String 转换成 InputStream 一个String (字串)。基础的实施方案实际
采用一个StringBuffer (字串缓冲)/作为一个数据源使用。通过将其同一个FilterInputStream 对象连
接,可提供一个有用的接口
FileInputStream 用于从文件读取信息 代表文件名的一个 String,或者一个 File 或FileDescriptor 对象
/作为一个数据源使用。通过将其同一个FilterInputStream 对象连接,可提供一个有用的接口
PipedInputString 产生为相关的 PipedOutputStream 写的数据。实现了“管道化”的概念
PipedOutputStream /作为一个数据源使用。通过将其同一个FilterInputStream 对象连接,可提供一个有用
的接口
SequenceInputStream 将两个或更多的 InputStream 对象转换成单个 InputStream 使用 两个InputStream对
象或者一个 Enumeration,用于 InputStream对象的一个容器/作为一个数据源使用。通过将其同一个
FilterInputStream 对象连接,可提供一个有用的接口
FilterInputStream 对作为破坏器接口使用的类进行抽象;那个破坏器为其他 InputStream类提供了有用的
功能。参见表 10。3 参见表 10。3 /参见表10。3
10。1。2 OutputStream 的类型
这一类别包括的类决定了我们的输入往何处去:一个字节数组(但没有String;假定我们可用字节数组创建
一个);一个文件;或者一个“管道”。
除此以外,FilterOutputStream 为“破坏器”类提供了一个基础类,它将属性或者有用的接口同输出流连接
起来。这将在以后讨论。
表 10。2 OutputStream 的类型
类 功能 构建器参数/如何使用
ByteArrayOutputStream 在内存中创建一个缓冲区。我们发送给流的所有数据都会置入这个缓冲区。 可选缓
冲区的初始大小/用于指出数据的目的地。若将其同FilterOutputStream 对象连接到一起,可提供一个有用
的接口
FileOutputStream 将信息发给一个文件 用一个 String 代表文件名,或选用一个File 或FileDescriptor 对
象/用于指出数据的目的地。若将其同FilterOutputStream 对象连接到一起,可提供一个有用的接口
PipedOutputStream 我们写给它的任何信息都会自动成为相关的PipedInputStream 的输出。实现了“管道
化”的概念 PipedInputStream /为多线程处理指出自己数据的目的地/将其同FilterOutputStream 对象连
接到一起,便可提供一个有用的接口
FilterOutputStream 对作为破坏器接口使用的类进行抽象处理;那个破坏器为其他 OutputStream 类提供了
有用的功能。参见表 10。4 参见表 10。4 /参见表10。4
10。2 增添属性和有用的接口
利用层次化对象动态和透明地添加单个对象的能力的做法叫作“装饰器”(Decorator)方案—— “方案”属
于本书第 16 章的主题(注释①)。装饰器方案规定封装于初始化对象中的所有对象都拥有相同的接口,以便
利用装饰器的“透明”性质——我们将相同的消息发给一个对象,无论它是否已被“装饰”。这正是在Java
IO库里存在“过滤器”(Filter)类的原因:抽象的“过滤器”类是所有装饰器的基础类(装饰器必须拥有
与它装饰的那个对象相同的接口,但装饰器亦可对接口作出扩展,这种情况见诸于几个特殊的“过滤器”类
中)。
子类处理要求大量子类对每种可能的组合提供支持时,便经常会用到装饰器——由于组合形式太多,造成子
类处理变得不切实际。Java IO 库要求许多不同的特性组合方案,这正是装饰器方案显得特别有用的原因。
但是,装饰器方案也有自己的一个缺点。在我们写一个程序的时候,装饰器为我们提供了大得多的灵活性
(因为可以方便地混合与匹配属性),但它们也使自己的代码变得更加复杂。原因在于Java IO 库操作不
便,我们必须创建许多类—— “核心”IO类型加上所有装饰器——才能得到自己希望的单个 IO 对象。
FilterInputStream 和FilterOutputStream (这两个名字不十分直观)提供了相应的装饰器接口,用于控制
一个特定的输入流(InputStream)或者输出流(OutputStream)。它们分别是从 InputStream和
OutputStream 衍生出来的。此外,它们都属于抽象类,在理论上为我们与一个流的不同通信手段都提供了一
286
…………………………………………………………Page 288……………………………………………………………
个通用的接口。事实上,FilterInputStream 和 FilterOutputStream 只是简单地模仿了自己的基础类,它们
是一个装饰器的基本要求。
10。2。1 通过 FilterInputStream 从 InputStream 里读入数据
FilterInputStream 类要完成两件全然不同的事情。其中,DataInputStream 允许我们读取不同的基本类型数
据以及 String 对象(所有方法都以“read ”开头,比如readByte(),readFloat()等等)。伴随对应的
DataOutputStream,我们可通过数据“流”将基本类型的数据从一个地方搬到另一个地方。这些“地方”是
由表10。1 总结的那些类决定的。若读取块内的数据,并自己进行解析,就不需要用到DataInputStream。但
在其他许多情况下,我们一般都想用它对自己读入的数据进行自动格式化。
剩下的类用于修改 InputStream 的内部行为方式:是否进行缓冲,是否跟踪自己读入的数据行,以及是否能
够推回一个字符等等。后两种类看起来特别象提供对构建一个编译器的支持(换言之,添加它们为了支持