文件过滤器的作用:在众多的文件中,筛选出符合条件的文件.例如在我的电脑中的,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对象