Java IO 概念 Java编程思想读书笔记

来源:互联网 发布:网络上赌博算不算诈骗 编辑:程序博客网 时间:2024/05/17 23:43

InputStream类型

InputStream的作用是用来表示那些从不同数据源产生输入的类,这些数据源包括:

1.字节数组

2.String对象

3.文件

4.“管道”,工作方式与实际管道相似,即,从一端输入,从另一端输出

6.其他数据源,如Internet连接等。

每一种数据源都有相应的InputStream子类。另外,FilterInputStream也属于一种InputStream,为“装饰器(decorator)”类提供基类。



OutputStream类型

OutputStream类决定了输出所要去往的目标:字节数组(但不是String,不过可以通过字节数组创建),文件或管道,FilterOutputStream为“装饰器”类提供了一个基类。


Java I/O类库需要多种不同功能的组合,这正是使用装饰器模式的理由。这也是Java I/O类库中存在filter(过滤器)类的原因,抽象类filter是所有装饰器类的基类。装饰器必须具有和它所装饰的对象相同的接口,但它也可以扩展接口,而这种情况只发生在个别filter类中。

但是,装饰器模式也有一个缺点:在编写程序时,它为我们提供了相当多的灵活性(因为我们可以很容易地混合和匹配属性),但是它同时也增加了代码的复杂性。Java I/O类库操作不便在于:我们必须创建许多类 -------- “核心”I/O类型加上所有有装饰器,才能得到我们所希望的单个I/O对象。

FilterInputStream和FilterOutputStream是用来提供装饰器类接口以控制特定输入流(InputStream)和输出流(OutputStream)的两个类,它们的名字并不直观。FilterInputStream和FilterOutputStream分别自I/O类库中基类InputStream和OutputStream派生而来,这两个类是装饰器的必须条件。


通过FilterInputStream从InputStream读取数据


我们几乎每次都要对输入进行缓冲 --------- 不管我们正在连接的是什么I/O设备,所以,I/O类库把无缓冲输入作为特殊情况(或只是方法调用)就显得更加合理了


通过FilterOutputStream向OutputStream写入

PrintStream最初的目的是为了以可视化格式打印所有的基本数据以及String对象,有两个重要方法:print()和println()。对它们重载,以便可打印出各种数据类型。

PrintStream可能会有一些问题,因为它捕捉了所有的IOExceptions(因此,我们必须使用checkError()自行测试错误状态,如果出现错误它返回true)。另外,PrintStream也未完全国际化,不能以平台无关的方式处理换行动作(这些问题在PrintWriter中得到解决)

BufferedOutputStream是一个修改过的OutputStream,它对数据流使用缓冲技术;因此每次向流写入时,不必每次都进行实际的物理写动作。所以在进行输出时,我们可能更经常使用它。



Reader和Writer

InputStream和OutputStream在以面向字节形式的I/O中重要的功能,而Reader和Writer则提供兼容Unicode与面向字符的I/O功能。

有时我们必须把来自于“字节”层次结构的类和“字符”层次结构中的类结合起来使用。为了实现这个目的,要用到”适配器“(adapter)类:InputStreamReader可以把InputStream转换为Reader,而OutputStreamWriter可以把OutputStream转换为Writer。

几乎所有的原始的Java I/O流类都具有相应的Reader和Writer类来提供天然的Unicode操作。然而在某些场合,面向字节的InputStream和OutputStream才是正确的解决方案;特别是,java.util.aip类库就是面向字节而不是面向字符的。因此,最明智的做法是尽量尝试使用Reader和Writer,一旦程序无法成功编译,我们就会发现自己不得不使用面向字节的类库。

下面的表展示在两个继承层次结构中,信息的来源和去处之间的对应关系:


体上,两个不同的继承层次结构中的接口即使不能说完全相同,但也是非常相似。


对于InputStream和OutputStream,我们使用FilterInputStream和FilterOutputStream的装饰器子类来修改”流"以满足特殊需要。Reader和Writer的类继承层次结构继续沿用相同的思想 --------- 但是并不完全相同

在下表中,相对于前一表格来说,左右之间的对应关系的近似程序更加粗略一些。造成这种差别的原因是因为类的组织形式不同,尽管BufferedOutputStream是FilterOutputStream的子类,但是BufferedWriter并不是FilterWriter的子类(尽管FilterWriter是抽象类,没有任何子类,把它放在那里也只是把它作为一个点位符或仅仅让我们不会对它所在位置产生疑惑)。然而,这些类的接口却十分相似。


一点很清楚:无论我们何时使用readLine(),都不应该使用DataInputStream(这会遭到编译器的强烈反对),而应该使用BufferedReader。除了这一点,DataInputStream仍是I/O类库的首选成员。

为了更容易地过渡到使用PrintWriter,它提供了一个既能接受Writer对象又能接受任何OutputStream对象的构造器。PrintWriter的格式化接口实际上与PrintStream相同。

在Java SE5中添加了PrintWriter构造器,以简化在将输出写入时文件创建过程。

有一种PrintWriter构造器还有一个选项,就是”自动执行清空“选项。如果构造器设置此选项,则在每个println()执行之后便会自动清空。


自我独立的类:RandomAccessFile

RandomAccessFile适用于大小已知的记录组成的文件,所以我们可以使用seek()将记录从一处转移到另一处,然后读取或者修改记录。文件中记录的大小不一定都相同,只要我们能够确定那些记录有多大以及它们在文件中的位置即可。

最初,我们可能难以相信RandomAccessFile不是InputStream或者OutputStream继承层次结构中的一部分。除了实现了DataInput和DataOutput接口(DataInputStream和DataOutputStream也实现了这两个接口)之外,它和这两个继承层次结构没有任何关联。它甚至不使用InputStream和OutputStream类已有的任何功能。它是一个完全独立的类,从头开始编写其所有的方法(大多数都是本地的)。这么做是因为RandomAccessFile拥有和别的I/O类型本质不同的行为,因为我们可以在一个文件内向前和向后移动。在任何情况下,它都是自我独立的,直接从Object派生而来。

从本质上来说,RandomAccessFile的工作方式类似于把DataInputStream和DataOutputStream组合起来使用,还添加了一些方法。其中方法getFilePointer()用于查找当前所处的文件位置,seek()用于在文件内移至新的位置,length()用于判断文件的最大尺寸。另外,其构造器还需要第二个参数用来指示我们只是“随机读”还是“既读又写”。它并不支持只写文件,这表明RandomAccessFile若是从DataInputStream继承而来也可能会运行得很好。 

只有RandomAccessFile支持搜寻方法,并且只适用于文件。BufferedInputStream却能允许标注(mark())位置(其值存储于内部某个简单变量内)和重新设定位置(reset()),但这些功能很有限,不是非常有用。

在JDK 1.4中,RandomAccessFile的大多数功能(但不是全部)由nio存储映射文件所取代。



0 0