程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 目錄列表器

目錄列表器

編輯:關於JAVA

現在假設我們想觀看一個目錄列表。可用兩種方式列出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]));
      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.*;

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();
              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 File(n).getName();
              return f.indexOf(afn) != -1;
            }
          });
    sort();
  }
  void print() {
    for(int i = 0; i < list.length; i++)
      System.out.println(list[i]);
  }
  private void sort() {
    StrSortVector sv = new StrSortVector();
    for(int i = 0; i < list.length; i++)
      sv.addElement(list[i]);
    // The first time an element is pulled from
    // the StrSortVector the list is sorted:
    for(int i = 0; i < list.length; i++)
      list[i] = sv.elementAt(i);
  }
  // Test it:
  public static void main(String[] args) {
    SortedDirList sd;
    if(args.length == 0)
      sd = new SortedDirList(null);
    else
      sd = new SortedDirList(args[0]);
    sd.print();
  }
} ///:~


這裡進行了另外少許改進。不再是將path(路徑)和list(列表)創建為main()的本地變量,它們變成了類的成員,使它們的值能在對象“生存”期間方便地訪問。事實上,main()現在只是對類進行測試的一種方式。大家可以看到,一旦列表創建完畢,類的構建器就會自動開始對列表進行排序。
這種排序不要求區分大小寫,所以最終不會得到一組全部單詞都以大寫字母開頭的列表,跟著是全部以小寫字母開頭的列表。然而,我們注意到在以相同字母開頭的一組文件名中,大寫字母是排在前面的——這對標准的排序來說仍是一種不合格的行為。Java 1.2已成功解決了這個問題。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved