JAVA中I/O流的应用
一、输入流:
1.1. 缓冲的输入文件
为打开一个文件以便输入,需要使用一个FileInputStream,同时将一个String或File对象作为文件名使用。为提高速度,最好先对文件进行缓冲处理,从而获得用于一个BufferedInputStream的构建器的结果句柄。为了以格式化的形式读取输入数据,我们将那个结果句柄赋给用于一个DataInputStream的构建器。DataInputStream是我们的最终(final)对象,并是我们进行读取操作的接口。
在这个例子中,只用到了readLine()方法,但理所当然任何DataInputStream方法都可以采用。一旦抵达文件末尾,readLine()就会返回一个null(空),以便中止并退出while循环。
“String s2”用于聚集完整的文件内容(包括必须添加的新行,因为readLine()去除了那些行)。随后,在本程序的后面部分中使用s2。最后,我们调用close(),用它关闭文件。从技术上说,会在运行finalize()时调用close()。而且我们希望一旦程序退出,就发生这种情况(无论是否进行垃圾收集)。然而,Java 1.0有一个非常突出的错误(Bug),造成这种情况不会发生。在Java 1.1中,必须明确调用System.runFinalizersOnExit(true),用它保证会为系统中的每个对象调用finalize()。然而,最安全的方法还是为文件明确调用close()。
1.2. 从内存输入
这一部分采用已经包含了完整文件内容的String s2,并用它创建一个StringBufferInputStream(字串缓冲输入流)——作为构建器的参数,要求使用一个String,而非一个StringBuffer)。随后,我们用read()依次读取每个字符,并将其发送至控制台。注意read()将下一个字节返回为int,所以必须将其造型为一个char,以便正确地打印。
1.3. 格式化内存输入
StringBufferInputStream的接口是有限的,所以通常需要将其封装到一个DataInputStream内,从而增强它的能力。然而,若选择用readByte()每次读出一个字符,那么所有值都是有效的,所以不可再用返回值来侦测何时结束输入。相反,可用available()方法判断有多少字符可用。下面这个例子展示了如何从文件中一次读出一个字符:
二、输入流:
2.1. 保存与恢复数据
PrintStream能格式化数据,使其能按我们的习惯阅读。但为了输出数据,以便由另一个数据流恢复,则需用一个DataOutputStream写入数据,并用一个DataInputStream恢复(获取)数据。当然,这些数据流可以是任何东西,但这里采用的是一个文件,并进行了缓冲处理,以加快读写速度。
注意字串是用writeBytes()写入的,而非writeChars()。若使用后者,写入的就是16位Unicode字符。由于DataInputStream中没有补充的“readChars”方法,所以不得不用readChar()每次取出一个字符。所以对ASCII来说,更方便的做法是将字符作为字节写入,在后面跟随一个新行;然后再用readLine()将字符当作普通的ASCII行读回。
writeDouble()将double数字保存到数据流中,并用补充的readDouble()恢复它。但为了保证任何读方法能够正常工作,必须知道数据项在流中的准确位置,因为既有可能将保存的double数据作为一个简单的字节序列读入,也有可能作为char或其他格式读入。所以必须要么为文件中的数据采用固定的格式,要么将额外的信息保存到文件中,以便正确判断数据的存放位置。
2.2. 读写随机访问文件
正如早先指出的那样,RandomAccessFile与IO层次结构的剩余部分几乎是完全隔离的,尽管它也实现了DataInput和DataOutput接口。所以不可将其与InputStream及OutputStream子类的任何部分关联起来。尽管也许能将一个ByteArrayInputStream当作一个随机访问元素对待,但只能用RandomAccessFile打开一个文件。必须假定RandomAccessFile已得到了正确的缓冲,因为我们不能自行选择。
可以自行选择的是第二个构建器参数:可决定以“只读”(r)方式或“读写”(rw)方式打开一个RandomAccessFile文件。
使用RandomAccessFile的时候,类似于组合使用DataInputStream和DataOutputStream(因为它实现了等同的接口)。除此以外,还可看到程序中使用了seek(),以便在文件中到处移动,对某个值作出修改。
3 快捷文件处理
由于以前采用的一些典型形式都涉及到文件处理,所以大家也许会怀疑为什么要进行那么多的代码输入——这正是装饰器方案一个缺点。本部分将向大家展示如何创建和使用典型文件读取和写入配置的快捷版本。
3.1. 快速文件输入
若想创建一个对象,用它从一个缓冲的DataInputStream中读取一个文件,可将这个过程封装到一个名为InFile的类内。