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

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

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


PushbackInputStream 有一个字节的后推缓冲区,以便后推读入的上一个字符 InputStream /通常由编译器 

在扫描器中使用,因为 Java 编译器需要它。一般不在自己的代码中使用  



10。2。2 通过 FilterOutputStream 向 OutputStream 里写入数据  



与DataInputStream 对应的是DataOutputStream,后者对各个基本数据类型以及String 对象进行格式化, 

并将其置入一个数据“流”中,以便任何机器上的 DataInputStream 都能正常地读取它们。所有方法都以 

 “wirte”开头,例如writeByte(),writeFloat()等等。  

若想进行一些真正的格式化输出,比如输出到控制台,请使用 PrintStream。利用它可以打印出所有基本数 

据类型以及 String 对象,并可采用一种易于查看的格式。这与DataOutputStream 正好相反,后者的目标是 

将那些数据置入一个数据流中,以便DataInputStream 能够方便地重新构造它们。System。out 静态对象是一 

个PrintStream。  

PrintStream 内两个重要的方法是print()和println() 。它们已进行了覆盖处理,可打印出所有数据类型。 

print()和 println()之间的差异是后者在操作完毕后会自动添加一个新行。  

BufferedOutputStream 属于一种“修改器”,用于指示数据流使用缓冲技术,使自己不必每次都向流内物理 

性地写入数据。通常都应将它应用于文件处理和控制器 IO。  

  

表 10。4 FilterOutputStream 的类型  

  

类 功能 构建器参数/如何使用  

  

DataOutputStream 与 DataInputStream 配合使用,以便采用方便的形式将基本数据类型(int,char,long 

等)写入一个数据流 OutputStream /包含了完整接口,以便我们写入基本数据类型  

PrintStream 用于产生格式化输出。DataOutputStream 控制的是数据的“存储”,而 PrintStream 控制的是 

 “显示” OutputStream ,可选一个布尔参数,指示缓冲区是否与每个新行一同刷新/对于自己的 

OutputStream 对象,应该用“final”将其封闭在内。可能经常都要用到它  



                                                                           287 


…………………………………………………………Page 289……………………………………………………………

BufferedOutputStream 用它避免每次发出数据的时候都要进行物理性的写入,要求它“请先在缓冲区里 

找”。可调用flush(),对缓冲区进行刷新 OutputStream ,可选缓冲区大小/本身并不能提供一个接口,只 

是发出使用缓冲区的要求。需要同一个接口对象连接到一起  



10。3 本身的缺陷:RandomAccessFile  



RandomAccessFile 用于包含了已知长度记录的文件,以便我们能用 seek()从一条记录移至另一条;然后读取 

或修改那些记录。各记录的长度并不一定相同;只要知道它们有多大以及置于文件何处即可。  

首先,我们有点难以相信RandomAccessFile 不属于 InputStream 或者OutputStream 分层结构的一部分。除 

了恰巧实现了DataInput 以及DataOutput (这两者亦由DataInputStream 和 DataOutputStream 实现)接口 

之外,它们与那些分层结构并无什么关系。它甚至没有用到现有 InputStream 或OutputStream 类的功能—— 

采用的是一个完全不相干的类。该类属于全新的设计,含有自己的全部(大多数为固有)方法。之所以要这 

样做,是因为RandomAccessFile 拥有与其他 IO类型完全不同的行为,因为我们可在一个文件里向前或向后 

移动。不管在哪种情况下,它都是独立运作的,作为Object 的一个“直接继承人”使用。  

从根本上说,RandomAccessFile 类似DataInputStream 和 DataOutputStream 的联合使用。其中, 

getFilePointer()用于了解当前在文件的什么地方,seek()用于移至文件内的一个新地点,而 length()用于 

判断文件的最大长度。此外,构建器要求使用另一个自变量(与C 的fopen()完全一样),指出自己只是随 

机读(〃r〃),还是读写兼施(〃rw〃)。这里没有提供对“只写文件”的支持。也就是说,假如是从 

DataInputStream 继承的,那么 RandomAccessFile 也有可能能很好地工作。  

还有更难对付的。很容易想象我们有时要在其他类型的数据流中搜索,比如一个 ByteArrayInputStream,但 

搜索方法只有RandomAccessFile 才会提供。而后者只能针对文件才能操作,不能针对数据流操作。此时, 

BufferedInputStream 确实允许我们标记一个位置(使用 mark(),它的值容纳于单个内部变量中),并用 

reset()重设那个位置。但这些做法都存在限制,并不是特别有用。  



10。4 File 类  



File 类有一个欺骗性的名字——通常会认为它对付的是一个文件,但实情并非如此。它既代表一个特定文件 

的名字,也代表目录内一系列文件的名字。若代表一个文件集,便可用list()方法查询这个集,返回的是一 

个字串数组。之所以要返回一个数组,而非某个灵活的集合类,是因为元素的数量是固定的。而且若想得到 

一个不同的目录列表,只需创建一个不同的File 对象即可。事实上,“FilePath ”(文件路径)似乎是一个 

更好的名字。本节将向大家完整地例示如何使用这个类,其中包括相关的 FilenameFilter (文件名过滤器) 

接口。  



10。4。1  目录列表器  



现在假设我们想观看一个目录列表。可用两种方式列出File 对象。若在不含自变量(参数)的情况下调用 

list(),会获得File 对象包含的一个完整列表。然而,若想对这个列表进行某些限制,就需要使用一个“目 

录过滤器”,该类的作用是指出应如何选择File 对象来完成显示。  

下面是用于这个例子的代码(或在执行该程序时遇到困难,请参考第 3 章 3。1。2 小节“赋值”):  

  

//: DirList。java  

// Displays directory listing  

package c10;  

import java。io。*;  

  

public class DirList {  

  public static void main(String'' args) {  

    try {  

      File path = new File(〃。〃);  

      String'' list;  

      if(args。length == 0)  

        list = path。list();  

      else   

        list = path。list(new DirFilter(args'0'));  



                                                                              288 


…………………………………………………………Page 290……………………………………………………………

      for(int i = 0; i 《 list。length; i++)  

        System。out。println(list'i');  

    } catch(Exception e) {  

      e。printStackTrace();  

    }  

  }  

}  

  

class DirFilter implements FilenameFilter {  

  String afn;  

  DirFilter(String afn) { this。afn = afn; }  

  public boolean accept(File dir; String name) {  

    // Strip path information:  

    String f = new File(name)。getName();  

    return f。indexOf(afn) != …1;  

  }  

} ///:~  

  

DirFilter 类“实现”了 interface FilenameFilter (关于接口的问题,已在第7 章进行了详述)。下面让 

我们看看FilenameFilter 接口有多么简单:  

  

public interface FilenameFilter {  

boolean accept(文件目录; 字串名);  

}  

  

它指出这种类型的所有对象都提供了一个名为 accept()的方法。之所以要创建这样的一个类,背后的全部原 

因就是把accept()方法提供给 list()方法,使 list()能够“回调”accept() ,从而判断应将哪些文件名包 

括到列表中。因此,通常将这种技术称为“回调”,有时也称为“算子”(也就是说,DirFilter 是一个算 

子,因为它唯一的作用就是容纳一个方法)。由于 list()采用一个 FilenameFilter 对象作为自己的自变量 

使用,所以我们能传递实现了 FilenameFilter 的任何类的一个对象,用它决定(甚至在运行期)list()方法 

的行为方式。回调的目的是在代码的行为上提供更大的灵活性。  

通过DirFilter,我们看出尽管一个“接口”只包含了一系列方法,但并不局限于只能写那些方法(但是, 

至少必须提供一个接口内所有方法的定义。在这种情况下,DirFilter 构建器也会创建)。  

accept()方法必须接纳一个 File 对象,用它指示用于寻找一个特定文件的目录;并接纳一个String,其中 

包含了要寻找之文件的名字。可决定使用或忽略这两个参数之一,但有时至少要使用文件名。记住 list()方 

法准备为目录对象中的每个文件名调用accept(),核实哪个应包含在内——具体由 accept()返回的“布尔” 

结果决定。  

为确定我们操作的只是文件名,其中没有包含路径信息,必须采用String 对象,并在它的外部创建一个 

File 对象。然后调用 getName(),它的作用是去除所有路径信息(采用与平台无关的方式)。随后,accept() 

用String 类的 indexOf()方法检查文件名内部是否存在搜索字串〃afn〃。若在字串内找到 afn,那么返回值就 

是afn 的起点索引;但假如没有找到,返回值就是…1。注意这只是一个简单的字串搜索例子,未使用常见的 

表达式“通配符”方案,比如〃fo?。b?r*〃;这种方案更难实现。  

list()方法返回的是一个数组。可查询这个数组的长度,然后在其中遍历,选定数组元素。与 C 和C++的类 

似行为相比,这种于方法内外方便游历数组的行为无疑是一个显著的进步。  

  

1。 匿名内部类  

下例用一个匿名内部类(已在第7 章讲述)来重写显得非常理想。首先创建了一个filter()方法,它返回指 

向FilenameFilter 的一个句柄:  

  

//: DirList2。java  

// Uses Java 1。1 anonymous inner classes  

import java。io。*;  



                                                                                       289 


…………………………………………………………Page 291……………………………………………………………

  

public class DirList2 {  

  public static FilenameFilter   

  filter(final String afn) {  

    // Creation of anonymous inner class:  

    return new FilenameFilter() {  

      String fn = afn;  

      public boolean accept(File dir; String n) {  

        // Strip path information:  

        String f = new File(n)。getName();  

        return f。indexOf(fn) != …1;  

      }  

    }; // End of anonymous inner class  

  }  

  public static void main(String'' args) {  

    try {  

      File path = new File(〃。〃);  

      String'' list;  

      if(args。length == 0)  

        list = path。list();  

      else   

        list = path。list(filter(args'0'));  

      for(int i = 0; i 《 list。length; i++)  

        System。out。println(list'i');  

    } catch(Exception e) {  

      e。printStackTrace();  

    }  

  }  

} ///:~  

  

注意 filter()的自变量必须是final。这一点是匿名内部类要求的,使其能使用来自本身作用域以外的一个 

对象。  

之所以认为这样做更好,是由于FilenameFilter 类现在同DirList2 紧密地结合在一起。然而,我们可采取 

进一步的操作,将匿名内部类定义成 list()的一个参数,使其显得更加精简。如下所示:  

  

//: DirList3。java  

// Building the anonymous inner class 〃in…place〃  

import java。io。*;  

  

public class DirList3 {  

  public static void main(final String'' args) {  

    try {  

      File path = new File(〃。〃);  

      String'' list;  

      if(args。length == 0)  

        list = path。list();  

      else   

        list = path。list(  

          new FilenameFilter() {  

            public boolean   

            accept(File dir; String n) {  

              String f = new File(n)。getName();  



                                                                                          290 


…………………………………………………………Page 292……………………………………………………………

              return f。indexOf(args'0') != …1;  

            }  

          });  

      for(int i = 0; i 《 list。length; i++)  

        System。out。println(list'i');  

    } catch(Exception e) {  

      e。printStackTrace();  

    }  

  }  

} ///:~  

  

main()现在的自变量是 final,因为匿名内部类直接使用args'0'。  

这展示了如何利用匿名内部类快速创建精简的类,以便解决一些复杂的问题。由于Java 中的所有东西都与类 

有关,所以它无疑是一种相当有用的编码技术。它的一个好处是将特定的问题隔离在一个地方统一解决。但 

在另一方面,这样生成的代码不是十分容易阅读,所以使用时必须慎重。  

  

2。 顺序目录列表  

经常都需要文件名以排好序的方式提供。由于 Java 1。0 和Java 1。1 都没有提供对排序的支持(从 Java 1。2 

开始提供),所以必须用第8 章创建的 SortVector将这一能力直接加入自己的程序。就象下面这样:  

  

//: SortedDirList。java  

// Displays sorted directory listing  

import java。io。*;  

import c08。*;  

  

public class SortedDirList {  

  private File path;  

  private String'' list;  

  public SortedDirList(final String afn) {  

    path = new File(〃。〃);  

    if(afn == null)  

      list = path。list();  

    else  

      list = path。list(  

          new FilenameFilter() {  

            public boolean   

            accept(File dir; String n) {  

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