按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
一次读出一个字符:
//: TestEOF。java
// Testing for the end of file while reading
// a byte at a time。
import java。io。*;
public class TestEOF {
public stat ic void main(String'' args) {
try {
DataInputStream in =
new DataInputStream(
new BufferedInputStream(
new FileInputStream(〃TestEof。java〃)));
while(in。available() != 0)
System。out。print((char)in。readByte());
} catch (IOException e) {
System。err。println(〃IOException〃);
}
}
} ///:~
注意取决于当前从什么媒体读入,avaiable()的工作方式也是有所区别的。它在字面上意味着“可以不受阻
塞读取的字节数量”。对一个文件来说,它意味着整个文件。但对一个不同种类的数据流来说,它却可能有
不同的含义。因此在使用时应考虑周全。
为了在这样的情况下侦测输入的结束,也可以通过捕获一个违例来实现。然而,若真的用违例来控制数据
流,却显得有些大材小用。
4。 行的编号与文件输出
这个例子展示了如何LineNumberInputStream 来跟踪输入行的编号。在这里,不可简单地将所有构建器都组
合起来,因为必须保持 LineNumberInputStream 的一个句柄(注意这并非一种继承环境,所以不能简单地将
in4造型到一个 LineNumberInputStream)。因此,li 容纳了指向 LineNumberInputStream 的句柄,然后在
它的基础上创建一个DataInputStream,以便读入数据。
这个例子也展示了如何将格式化数据写入一个文件。首先创建了一个 FileOutputStream,用它同一个文件连
接。考虑到效率方面的原因,它生成了一个BufferedOutputStream。这几乎肯定是我们一般的做法,但却必
须明确地这样做。随后为了进行格式化,它转换成一个PrintStream。用这种方式创建的数据文件可作为一
个原始的文本文件读取。
标志DataInputStream 何时结束的一个方法是 readLine()。一旦没有更多的字串可以读取,它就会返回
null 。每个行都会伴随自己的行号打印到文件里。该行号可通过li 查询。
可看到用于 out1 的、一个明确指定的close()。若程序准备掉转头来,并再次读取相同的文件,这种做法就
显得相当有用。然而,该程序直到结束也没有检查文件IODemo。txt。正如以前指出的那样,如果不为自己的
所有输出文件调用 close(),就可能发现缓冲区不会得到刷新,造成它们不完整。
297
…………………………………………………………Page 299……………………………………………………………
10。5。2 输出流
两类主要的输出流是按它们写入数据的方式划分的:一种按人的习惯写入,另一种为了以后由一个
DataInputStream 而写入。RandomAccessFile 是独立的,尽管它的数据格式兼容于 DataInputStream 和
DataOutputStream。
5。 保存与恢复数据
PrintStream 能格式化数据,使其能按我们的习惯阅读。但为了输出数据,以便由另一个数据流恢复,则需
用一个DataOutputStream 写入数据,并用一个DataInputStream 恢复(获取)数据。当然,这些数据流可以
是任何东西,但这里采用的是一个文件,并进行了缓冲处理,以加快读写速度。
注意字串是用writeBytes()写入的,而非writeChars()。若使用后者,写入的就是16 位Unicode 字符。由
于DataInputStream 中没有补充的“readChars”方法,所以不得不用 readChar()每次取出一个字符。所以
对ASCII 来说,更方便的做法是将字符作为字节写入,在后面跟随一个新行;然后再用 readLine()将字符当
作普通的ASCII 行读回。
writeDouble()将 double 数字保存到数据流中,并用补充的 readDouble()恢复它。但为了保证任何读方法能
够正常工作,必须知道数据项在流中的准确位置,因为既有可能将保存的 double 数据作为一个简单的字节序
列读入,也有可能作为 char 或其他格式读入。所以必须要么为文件中的数据采用固定的格式,要么将额外的
信息保存到文件中,以便正确判断数据的存放位置。
6。 读写随机访问文件
正如早先指出的那样,RandomAccessFile 与 IO层次结构的剩余部分几乎是完全隔离的,尽管它也实现了
DataInput 和DataOutput 接口。所以不可将其与 InputStream及 OutputStream 子类的任何部分关联起来。
尽管也许能将一个ByteArrayInputStream 当作一个随机访问元素对待,但只能用RandomAccessFile打开一
个文件。必须假定 RandomAccessFile 已得到了正确的缓冲,因为我们不能自行选择。
可以自行选择的是第二个构建器参数:可决定以“只读”(r)方式或“读写”(rw)方式打开一个
RandomAccessFile 文件。
使用RandomAccessFile 的时候,类似于组合使用DataInputStream 和 DataOutputStream (因为它实现了等
同的接口)。除此以外,还可看到程序中使用了seek(),以便在文件中到处移动,对某个值作出修改。
10。5。3 快捷文件处理
由于以前采用的一些典型形式都涉及到文件处理,所以大家也许会怀疑为什么要进行那么多的代码输入——
这正是装饰器方案一个缺点。本部分将向大家展示如何创建和使用典型文件读取和写入配置的快捷版本。这
些快捷版本均置入package。bruceeckel。tools 中(自第5 章开始创建)。为了将每个类都添加到库内,
只需将其置入适当的目录,并添加对应的package 语句即可。
7。 快速文件输入
若想创建一个对象,用它从一个缓冲的DataInputStream 中读取一个文件,可将这个过程封装到一个名为
InFile 的类内。如下所示:
//: InFile。java
// Shorthand class for opening an input file
package 。bruceeckel。tools;
import java。io。*;
public class InFile extends DataInputStream {
public InFile(String filename)
throws FileNotFoundException {
super(
new BufferedInputStream(
new FileInputStream(filename)));
}
public InFile(File file)
298
…………………………………………………………Page 300……………………………………………………………
throws FileNotFoundException {
this(file。getPath());
}
} ///:~
无论构建器的String 版本还是File 版本都包括在内,用于共同创建一个 FileInputStream。
就象这个例子展示的那样,现在可以有效减少创建文件时由于重复强调造成的问题。
8。 快速输出格式化文件
亦可用同类型的方法创建一个PrintStream,令其写入一个缓冲文件。下面是对。bruceeckel。tools 的扩
展:
//: PrintFile。java
// Shorthand class for opening an output file
// for human…readable output。
package 。bruceeckel。tools;
import java。io。*;
public class PrintFile extends PrintStream {
public PrintFile(String filename)
throws IOException {
super(
new BufferedOutputStream(
new FileOutputStream(filename)));
}
public PrintFile(File file)
throws IOException {
this(file。getPath()