友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
第三电子书 返回本书目录 加入书签 我的书架 我的书签 TXT全本下载 『收藏到我的浏览器』

Java编程思想第4版[中文版](PDF格式)-第74部分

快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!


System。runFinalizersOnExit(true),用它保证会为系统中的每个对象调用finalize()。然而,最安全的方 

法还是为文件明确调用 close()。  

  

2。 从内存输入  

这一部分采用已经包含了完整文件内容的String s2,并用它创建一个 StringBufferInputStream (字串缓冲 



                                                                                          296 


…………………………………………………………Page 298……………………………………………………………

输入流)——作为构建器的参数,要求使用一个 String,而非一个 StringBuffer)。随后,我们用read() 

依次读取每个字符,并将其发送至控制台。注意read()将下一个字节返回为 int,所以必须将其造型为一个 

char,以便正确地打印。  

  

3。 格式化内存输入  

StringBufferInputStream 的接口是有限的,所以通常需要将其封装到一个DataInputStream 内,从而增强 

它的能力。然而,若选择用readByte()每次读出一个字符,那么所有值都是有效的,所以不可再用返回值来 

侦测何时结束输入。相反,可用available()方法判断有多少字符可用。下面这个例子展示了如何从文件中 

一次读出一个字符:  

  

//: 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());  

  }  

} ///:~  

  

注意构建器不可能捕获一个由基础类构建器“掷”出的违例。  

  

9。 快速输出数据文件  

最后,利用类似的快捷方式可创建一个缓冲输出文件,用它保存数据(与由人观看的数据格式相反):  

  

//: OutFile。java  

// Shorthand class for opening an output file  

// for data storage。  

package 。bruceeckel。tools;  

import java。io。*;  

  

public class OutFile extends DataOutputStream {  

  public OutFile(String filename)  

    throws IOException {  

    super(  

      new BufferedOutputStream(  

        new FileOutputStream(filename)));  

  }  

  public OutFile(File file)  

    throws IOException {  

    this(file。getPath());  



                                                                                          299 


…………………………………………………………Page 301……………………………………………………………

  }  

} ///:~  

  

非常奇怪的是(也非常不幸),Java 库的设计者居然没想到将这些便利措施直接作为他们的一部分标准提 

供。  



10。5。4 从标准输入中读取数据  



以Unix 首先倡导的“标准输入”、“标准输出”以及“标准错误输出”概念为基础,Java 提供了相应的 

System。in,System。out 以及System。err。贯这一整本书,大家都会接触到如何用 System。out进行标准输 

出,它已预封装成一个 PrintStream 对象。System。err 同样是一个PrintStream,但System。in 是一个原始 

的InputStream,未进行任何封装处理。这意味着尽管能直接使用 System。out 和System。err,但必须事先封 

装System。in,否则不能从中读取数据。  

典型情况下,我们希望用readLine()每次读取一行输入信息,所以需要将System。in 封装到一个 

DataInputStream 中。这是Java 1。0 进行行输入时采取的“老”办法。在本章稍后,大家还会看到 Java 1。1 

的解决方案。下面是个简单的例子,作用是回应我们键入的每一行内容:  

  

//: Echo。java  

// How to read from standard input  

import java。io。*;  

  

public class Echo {  

  public static void main(String'' args) {  

    DataInputStream in =  

      new DataInputStream(  

        new BufferedInputStream(System。in));  

    String s;  

    try {  

      while((s = in。readLine())。length() != 0)  

        System。out。println(s);  

      // An empty line terminates the program  

    } catch(IOException e) {  

      e。printStackTrace();  

    }  

  }  

} ///:~  

  

之所以要使用try 块,是由于 readLine()可能“掷”出一个 IOException。注意同其他大多数流一样,也应 

对System。in 进行缓冲。  

由于在每个程序中都要将System。in 封装到一个 DataInputStream 内,所以显得有点不方便。但采用这种设 

计方案,可以获得最大的灵活性。  



10。5。5 管道数据流  



本章已简要介绍了 PipedInputStream (管道输入流)和PipedOutputStream (管道输出流)。尽管描述不十 

分详细,但并不是说它们作用不大。然而,只有在掌握了多线程处理的概念后,才可真正体会它们的价值所 

在。原因很简单,因为管道化的数据流就是用于线程之间的通信。这方面的问题将在第 14 章用一个示例说 

明。  



10。6 StreamTokenizer  



尽管StreamTokenizer 并不是从 InputStream或 OutputStream 衍生的,但它只随同 InputStream工作,所以 

十分恰当地包括在库的 IO部分中。  

StreamTokenizer 类用于将任何 InputStream分割为一系列“记号”(Token)。这些记号实际是一些断续的 



                                                                                       300 


…………………………………………………………Page 302……………………………………………………………

文本块,中间用我们选择的任何东西分隔。例如,我们的记号可以是单词,中间用空白(空格)以及标点符 

号分隔。  

下面是一个简单的程序,用于计算各个单词在文本文件中重复出现的次数:  

  

//: SortedWordCount。java  

// Counts words in a file; outputs  

// results in sorted form。  

import java。io。*;  

import java。util。*;  

import c08。*; // Contains StrSortVector  

  

class Counter {  

  private int i = 1;  

  int read() { return i; }  

  void increment() { i++; }  

}  

  

public class SortedWordCount {  

  private FileInputStream file;  

  private StreamTokenizer st;  

  private Hashtable counts = new Hashtable();  

  SortedWordCount(String filename)  

    throws FileNotFoundException {  

    try {  

      file = new FileInputStream(file
返回目录 上一页 下一页 回到顶部 1 1
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!