文件過濾器的作用:在眾多的文件中,篩選出符合條件的文件.例如在我的電腦中的,D:\文檔\瀏覽器下載目錄下,篩選出所有的以.exe或者.pdf等等結尾的文件
在java中,專門提供了文件過濾器接口.
public interface FilenameFilter accept(File dirs,String name)
public interface FileFilter accept(File pathname);
這兩個過濾器中,實現文件過濾功能的函數正是accept,接口中也只有一個函數.
在使用時,要對過濾器接口進行實現
區別:
FilenameFilter中的accept函數接收的是兩個參數:指定父目錄的路徑和父目錄路徑中所有的子文件或者子文件夾,需要將這兩個參數封裝成File的對象再使用File中的功能
FileFilter中的accept函數接收的則直接是:完整的路徑,即需要進行過濾操作的文件或文件夾,直接可以使用File中的功能
要想完成過濾功能,同時還需要File類中的兩個函數:
1)public String[] list(FilenameFilter filter) 將滿足過濾器條件的以數組形式返回
2)public File[] listFiles(FilenameFilter filter) 將滿足過濾器條件的以File對象數組的形式返回
1 public String[] list(FilenameFilter filter) { 2 String names[] = list(); 3 if ((names == null) || (filter == null)) { 4 return names; 5 } 6 List<String> v = new ArrayList<>(); 7 for (int i = 0 ; i < names.length ; i++) { 8 if (filter.accept(this, names[i])) { 9 v.add(names[i]); 10 } 11 } 12 return v.toArray(new String[v.size()]); //從源代碼中可以看到,list返回的是一個string類型的數組,而listFile返回的是File對象數組(下面可以看到) 13 }
從源代碼中可以看到,list返回的是一個String類型的數組,而listFiles返回的是File對象數組(在下面會附源代碼)
這兩個函數的參數也可以是(FileFilter filter),操作更為簡單
以FilenameFilter為例,分別使用list和listFiles()
1 public boolean accept(File dir, String name) { 2 //先判斷是否以.exe后綴結尾 3 boolean matched = name.endsWith(".exe"); 4 //將dir和name封裝成一個File對象,再使用File中的功能 5 File f = new File(dir,name); 6 boolean isFile = f.isFile(); 7 8 return matched && isFile; 9 }
主函數中:
1 public static void main(String[] args) { 2 //創建父目錄File類的對象parent 3 File parent = new File("D:\\文檔\\瀏覽器下載"); 4 //創建文件過濾器的對象 5 MyFilenameFilter my = new MyFilenameFilter(); 6 method_1(parent, my); 7 8 } 9 private static void method_1(File parent, MyFilenameFilter my) { 10 //使用parent調用list.返回的是子文件或者子文件夾,下面需要封裝 11 String[] names = parent.list(my); 12 for(String name : names){ 13 //System.out.println(name); 14 File file = new File(parent,name); 15 String path = file.getAbsolutePath(); 16 System.out.println(file); 17 System.out.println(path); 18 } 19 }
如果使用listFile()的話,返回的直接是滿足條件的文件對象數組
1 private static void method_2(File parent, MyFilenameFilter my) { 2 //使用parent調用listfiles,返回的是File對象數組,下面不需要封裝 3 File[] names = parent.listFiles(my); 4 for(File name : names){ 5 File path = name.getAbsoluteFile(); 6 System.out.println(name); 7 System.out.println(path); 8 } 9 10 }
如果使用FileFilter的話
1 public boolean accept(File pathname) { 2 //pathname是一個File對象,可以直接調用File中的功能 3 boolean matched = pathname.getName().endsWith(suffix); 4 boolean isFile = pathname.isFile(); 5 return matched && isFile ; 6 }
1 public static void main(String[] args) { 2 //創建父目錄File類的對象parent 3 File parent = new File("D:\\文檔\\瀏覽器下載"); 4 //創建文件過濾器的對象 5 MyFileFilter fileFilter = new MyFileFilter(); 6 method_3(parent, fileFilter); 7 8 } 9 10 private static void method_3(File parent, MyFileFilter fileFilter) { 11 // 12 File[] names = parent.listFiles(fileFilter); 13 for(File name : names){ 14 System.out.println(name); 15 } 16 }
以上便是我們要使用過濾器的話,需要實現的代碼.
那么問題又來了,accept函數到底是什么時候被調用執行的呢?這個和底層的源代碼有關.
1 public File[] listFiles(FilenameFilter filter) { 2 String ss[] = list(); 3 if (ss == null) return null; 4 ArrayList<File> files = new ArrayList<>(); 5 for (String s : ss) 6 if ((filter == null) || filter.accept(this, s)) //accept的主要區別在這.accept需要接收兩個參數,並由我們手動完成封裝 7 files.add(new File(s, this)); 8 return files.toArray(new File[files.size()]); 9 }
1 public File[] listFiles(FileFilter filter) { 2 String ss[] = list(); 3 if (ss == null) return null; 4 ArrayList<File> files = new ArrayList<>(); 5 for (String s : ss) { 6 File f = new File(s, this); //底層自動幫我們對s和this進行了封裝,最后accept只需要接收一個File對象就可以了 7 if ((filter == null) || filter.accept(f)) 8 files.add(f); 9 } 10 return files.toArray(new File[files.size()]); 11 }
為了便於理解,我下面上傳一張圖片來演示底層的調用
注意辣:如果給定的parent(一開始指定的)的文件目錄是有問題的,那么就會出現空指針異常.
這樣的話,調用過程就比較清晰了.
最后,把程序改進以下,使得可以根據用戶的需求,更改篩選的目標,使可以篩選不同后綴名的文件.
可以通過文件過濾器的構造函數來傳遞這個表示后綴的參數
1 public class MyFileFilter implements FileFilter{ 2 public String suffix; 3 MyFileFilter(String suffix){ 4 this.suffix = suffix; 5 } 6 7 @Override 8 public boolean accept(File pathname) { 9 // 10 boolean matched = pathname.getName().endsWith(suffix); 11 boolean isFile = pathname.isFile(); 12 return matched && isFile ; 13 } 14 15 }
1 public static void main(String[] args) { 2 //創建父目錄File類的對象parent 3 File parent = new File("D:\\文檔\\瀏覽器下載"); 4 //創建文件過濾器的對象 5 MyFileFilter fileFilter = new MyFileFilter(".exe"); //在創建對象的時候傳遞suffix的參數就可以了 6 }
以上關於文件過濾器的理解已經比較透徹了.
總結一下吧:
可以使用FilenameFilter 和FileFilter過濾器,兩者中的accept函數所需要的參數不一樣,對應的操作也不一樣,FilenameFilter的accept需要兩個參數,而FileFilter的則是File對象
list(FilenameFilter filter) 返回的是string數組,其中存的就是滿足過濾器條件的子文件或者子文件夾
listFiles(FilenameFilter/FileFilter filter) 返回是對象數組,存的是滿足過濾器條件的File對象