转载自 探究Java File类中list()、listFiles()的使用及区别,认识和使用匿名内部类
内容概要:
1、认识File类;
2、File的构造函数;
3、list()及其重载方法的使用,匿名内部类的两种使用方式;
4、listFiles()方法和list()方法的区别,listFiles()及其重载方法的使用。
--------------------------------1、认识File类--------------------------------
File类的名字会有一定的误导性:我们很容易的认为它指代的是文件。实际上并不是这样的。
其实它解决的是文件或者是文件夹的路径问题。如果使用FilePath这个名字会更好些(可惜Java最初没有这么做)。
--------------------------------2、File的构造函数---------------------------
File类的构造函数有以下几种:
1)、File(String pathname)
2)、File(String parent, String child)
3)、File(File parent, String child)
4)、File(URI uri)
构造的File类对象表示一个路径,指向我们的目标文件或文件夹。
File path = new File("."); 表示当前目录。
File path = new File("E:\\Java"); 表示Windows下的E盘里的Java文件(或者是文件夹),注意要用双斜线\\。
File path = new File(new File("."),"bin"); 表示当前文件夹下的bin文件(文件夹),如果没有bin就会抛出NullPointerException异常。
--------------------------------3、list()及其重载方法的使用,匿名内部类的两种使用方式---------------------------
list()方法 : 会返回一个字符数组,将制定路径下的文件或文件夹名字存储到String数组中。因为其返回的是一个String类型的数组,所以它也就只是一个名字而已(后面要讲到的listFiles()及其重载方法则不同,它们返回的是File类型的对象,所以具有其全部的属性和方法)。有以下两种重载方式:
1)、String[] list()
2)、String[] list(FilenameFilter filter)
下面是File构造函数和list()方法的简单应用:
package com.lj95801.iosystem; import java.io.File; import org.junit.Test; public class tFile1 { /* * File类的构造函数有以下几种: * 1)、File(File parent, String child); * 2)、File(String pathname) * 3)、File(String parent, String child) * 4)、File(URI uri) */ @Test public void test1(){ //1、new File(".")构建的是当前目录的路径 File path = new File("."); String[] list = path.list(); for(String itemName : list){ System.out.println(itemName); } //2、new File("E:\\Java")利用绝对路径构建E盘下的Java目录路径 System.out.println("--------->"); path = new File("E:\\Java"); list = path.list(); for(String itemName : list){ System.out.println(itemName); } //3、new File(new File("."),"bin")表示当前目录下的bin目录 System.out.println("--------->"); path = new File(new File("."),"bin"); list = path.list();//列出bin目录下的所有文件或者是文件夹 for(String itemName : list){ System.out.println(itemName); } }
}
运行结果如下:
下面进一步讲String[] list(FilenameFilter filter)和匿名内部类的用法。
FilenameFilter filter是一个目录过滤器。list(FilenameFilter filter)方法会选择符合条件的文件或文件夹。为了能理解这个函数的工作原理,下面列出了其源码(这个是Java类库中的源码,注释是我自己添加的):
public String[] list(FilenameFilter filter) { String names[] = list(); //首先还是调用<span style="font-family: Arial, Helvetica, sans-serif;">list()方法,获取指定目录下的全部文件(夹)名字</span> if ((names == null) || (filter == null)) { //<span style="font-family: Arial, Helvetica, sans-serif;">filter == null说明没有过滤条件</span> return names; } ArrayList v = new ArrayList(); for (int i = 0 ; i < names.length ; i++) { //遍历names[]数组中的所有文件(夹)名字 if (filter.accept(this, names[i])) { //如果<span style="font-family: Arial, Helvetica, sans-serif;">accept()方法返回真,则添加到ArrayList中</span> v.add(names[i]); } } return (String[])(v.toArray(new String[v.size()])); //将<span style="font-family: Arial, Helvetica, sans-serif;">ArrayList转换成String[]类型返回</span> }
可以看出,list(FilenameFilter filter)方法保存的是那些能够使filter.accept()方法返回true的文件名。
list(FilenameFilter filter)的原理明白了,现在的问题是accept()方法又是怎么回事呢?
首先,filter.accept(this, names[i]);就可以看出,这是FilenameFilter中的方法。继续往上追溯FilenameFilter的源代码如下:
public interface FilenameFilter { /** * Tests if a specified file should be included in a file list. * * @param dir the directory in which the file was found. * @param name the name of the file. * @return <code>true</code> if and only if the name should be * included in the file list; <code>false</code> otherwise. */ boolean accept(File dir, String name);
}
好!!终于明白了,FilenameFilter是一个接口。
现在理一下思路:
list(FilenameFilter filter)方法 ---------调用了-------> filter对象中的accept(File dir, String name)方法 ------> FilenameFilter是一个接口。
accept()方法会返回一个boolean类型的值,list()方法会根据这个返回值来决定是不是要将某个名字添加到返回列表中。所以,我们要在accept()方法中定义好挑选条件,由于是字符的选取,这会用到正则表达式。
所以,要使用list(FilenameFilter filter)方法就必须实现FilenameFilter接口,accept方法由我们自己定义,所以你想要让什么样的文件名能够使得accept方法返回ture(等价的就是你想要什么样的文件名能够被list方法返回)都由你自己决定了。
下面来看一看如何使用list(FilenameFilter filter)方法:
package com.lj95801.iosystem; import java.io.File;
import java.io.FileFilter;
import java.io.FilenameFilter;
import java.util.regex.Pattern; import org.junit.Test; public class tFile2 { /* * list()方法 : 会返回一个字符数组,将制定路径下的文件或文件夹名(仅仅是个名字而已)存储到String数组中。有<span style="white-space:pre"> </span> * 以下几种: * 1)、list() * 2)、list(FilenameFilter filter) * * FilenameFilter filter是一个目录过滤器。list(FilenameFilter filter)方法会选择 * 符合条件的文件或文件夹。为了能理解这个函数的工作原理,下面列出了其源码: * public String[] list(FilenameFilter filter) { String names[] = list(); if ((names == null) || (filter == null)) { return names; } ArrayList v = new ArrayList(); for (int i = 0 ; i < names.length ; i++) { if (filter.accept(this, names[i])) { v.add(names[i]); } } return (String[])(v.toArray(new String[v.size()])); } *我们再往前追踪一下,看看FilenameFilter到底是怎样的,同时其accept()方法又有什么作用: * interface FilenameFilter { * * Tests if a specified file should be included in a file list. * * @param dir the directory in which the file was found. * @param name the name of the file. * @return <code>true</code> if and only if the name should be * included in the file list; <code>false</code> otherwise. boolean accept(File dir, String name); } * *我们可以看到,FilenameFilter只是一个接口,所以如果要用list(FilenameFilter filter)方法 *我们必须要实现这样的一个接口。accept()方法会返回一个boolean类型的值,list()方法会根据这个返回值 *来决定是不是要将某个名字添加到返回列表中。所以,我们要在accept()方法中定义好挑选条件,这会用到正则表达式。 * */ //一、采用实现接口的方式 class FileNameFilter1 implements FilenameFilter{ private Pattern pattern; public FileNameFilter1(String regex) { pattern = Pattern.compile(regex); } @Override public boolean accept(File dir, String name) { boolean result = pattern.matcher(name).matches(); return result; } } /* * 二、采用匿名内部类的方式。 * 不用implements的方式来实现接口,但是定义一个静态方法,此静态方法返回一个FilenameFilter对象, * 本来正常的语句是return new FilenameFilter();但是在语句结束之前我说“等一下,我要在这里定义 * 一个类,类的具体实现我用一个大括号括起来”。 */ static class FileNameFilter2{ public static FilenameFilter filter(final String regex){ return new FilenameFilter(){ private Pattern pattern = Pattern.compile(regex); @Override public boolean accept(File dir, String name) { return pattern.matcher(name).matches(); } }; } } @Test public void test2(){ System.out.println("------挑选当前目录下以.开头的文件或文件夹-------"); //1、挑选当前目录下以.开头的文件或文件夹,并且打印出来(创建一个类来实现FilenameFilter接口) File path = new File("."); String[] nameList = path.list(new FileNameFilter1("\\..*")); for(String itemName : nameList){ System.out.println(itemName); } System.out.println("------挑选当前目录下以b开头的文件或文件夹-------"); //2、挑选当前目录下以b开头的文件或文件夹,并且打印出来(使用匿名内部类的方式来实现) File path2 = new File("."); String[] nameList2 = path2.list(FileNameFilter2.filter("b.*")); for(String itemName : nameList2){ System.out.println(itemName); } System.out.println("------挑选当前目录下以s开头的文件或文件夹-------"); //3、将匿名内部类利用到极致 File path3 = new File("."); String[] nameList3 = path3.list(new FilenameFilter(){//其实是在第二种方式的基础上精简过来的。 private Pattern pattern = Pattern.compile("s.*"); @Override public boolean accept(File dir, String name) { return pattern.matcher(name).matches(); } }); for(String itemName : nameList3){ System.out.println(itemName); } }
}
执行结果如下:
--------------------------------4、listFiles()方法和list()方法的区别,listFiles()及其重载方法的使用---------------
list()和listFiles()方法的区别在于:
list()返回的是一个String类型数组,它只是一个数组,仅仅只是一个文件(文件夹)的名字而已;
而listFiles()方法返回的是一个File类的引用,它具有类的所有属性和方法,比如:String getName()
方法就能够返回该文件的String类型的文件名(名字而已)。
下面的前三个方法返回File[]类型,第四个返回static File[]类型。
返回类型 : 该路径下所有文件或文件夹的绝对路径(pathname,注意File类型指的是路径,而不是文件)
listFiles()
listFiles(FileFilter filter)
listFiles(FilenameFilter filter)
listRoots()
我们可以追踪一下FileFilter接口的源代码,加深理解(其实和FilenameFilter差不多):
public interface FileFilter { /** * Tests whether or not the specified abstract pathname should be * included in a pathname list. * * @param pathname The abstract pathname to be tested * @return <code>true</code> if and only if <code>pathname</code> * should be included */ boolean accept(File pathname); }
也要实现accept方法,但是传入的参数不一样,它是File类型的。这样的话就好办了。
比如说,我要挑选文件夹:
class FileDirectory implements FileFilter{ @Override public boolean accept(File pathname) { return pathname.isDirectory(); }
}
再比如说,我要挑选可执行文件:
class FileDirectory implements FileFilter{ @Override public boolean accept(File pathname) { return pathname.canExecute(); }
}
下面给出一个例子,说明用法:
package com.lj95801.iosystem; import java.io.File;
import java.io.FileFilter;
import java.io.FilenameFilter;
import java.util.regex.Pattern; import org.junit.Test; public class tFile3 { /* * list()和listFiles()方法的区别在于:list()返回的是一个String类型数组,它只是一个数组; * 而listFiles()方法返回的是一个File类的引用,它具有类的所有属性和方法。 * * 下面的前三个方法返回File[]类型,第四个返回static File[]类型。 * 返回类型 : 该路径下所有文件或文件夹的绝对路径(pathname,注意File类型指的是路径,而不是文件) * listFiles() * listFiles(FileFilter filter) * listFiles(FilenameFilter filter) * listRoots() * */ @Test public void test3(){ System.out.println("-----判别当前目录下的文件是否为文件夹----"); //1、列出当前目录下的所有文件和文件夹,保存为File类对象的数组,判别其是否为文件夹 File path = new File("."); File[] files = path.listFiles(); for(File f : files){ System.out.println(f + " ---> is a Directory? " + f.isDirectory()); } System.out.println("-----挑选出当前目录下的所有文件夹----"); //2、挑选出当前目录下的所有文件夹 File path2 = new File("."); File[] files2 = path2.listFiles(new FileFilter(){ @Override public boolean accept(File pathname) { return pathname.isDirectory(); } }); for(File f : files2){ System.out.println(f); } System.out.println("-----挑选出当前目录下的所有以s开头的文件夹----"); //2、挑选出当前目录下的所有以s开头的文件夹 File path3 = new File("."); File[] files3 = path3.listFiles(new FileFilter(){ @Override public boolean accept(File pathname) { Pattern pattern = Pattern.compile("s.*"); return pathname.isDirectory()&&pattern.matcher(pathname.getName()).matches(); } }); for(File f : files3){ System.out.println(f); } System.out.println("-----挑选出当前目录下的所有以.开头的文件夹,并且标明文件属性----"); //3、挑选出当前目录下以.开头的文件或文件夹,并且在其后部标明f/d标明其为文件或文件夹 File path4 = new File("."); File[] files4 = path4.listFiles(new FilenameFilter(){ Pattern pattern = Pattern.compile("\\..*"); @Override public boolean accept(File dir, String name) { return pattern.matcher(name).matches(); } }); for(File f : files4){ String sfd = (f.isFile()) ? "f" : "d"; System.out.println(f.getName() + "---->" + sfd); } }
}
执行结果如下:
----------------------------------------------下面是整个演示源代码----------------------------------------------
package com.lj95801.iosystem; import java.io.File;
import java.io.FileFilter;
import java.io.FilenameFilter;
import java.util.regex.Pattern; import org.junit.Test; public class tFile1 { /* * File类的构造函数有以下几种: * 1)、File(File parent, String child); * 2)、File(String pathname) * 3)、File(String parent, String child) * 4)、File(URI uri) */ @Test public void test1(){ //1、new File(".")构建的是当前目录的路径 File path = new File("."); String[] list = path.list(); for(String itemName : list){ System.out.println(itemName); } //2、new File("E:\\Java")利用绝对路径构建E盘下的Java目录路径 System.out.println("--------->"); path = new File("E:\\Java"); list = path.list(); for(String itemName : list){ System.out.println(itemName); } //3、new File(new File("."),"bin")表示当前目录下的bin目录 System.out.println("--------->"); path = new File(new File("."),"bin"); list = path.list();//列出bin目录下的所有文件或者是文件夹 for(String itemName : list){ System.out.println(itemName); } } /* * list()方法 : 会返回一个字符数组,将制定路径下的文件或文件夹名(仅仅是个名字而已)存储到String数组中。有以下几种: * 1)、list() * 2)、list(FilenameFilter filter) * * FilenameFilter filter是一个目录过滤器。list(FilenameFilter filter)方法会选择 * 符合条件的文件或文件夹。为了能理解这个函数的工作原理,下面列出了其源码: * public String[] list(FilenameFilter filter) { String names[] = list(); if ((names == null) || (filter == null)) { return names; } ArrayList v = new ArrayList(); for (int i = 0 ; i < names.length ; i++) { if (filter.accept(this, names[i])) { v.add(names[i]); } } return (String[])(v.toArray(new String[v.size()])); } *我们再往前追踪一下,看看FilenameFilter到底是怎样的,同时其accept()方法又有什么作用: * interface FilenameFilter { * * Tests if a specified file should be included in a file list. * * @param dir the directory in which the file was found. * @param name the name of the file. * @return <code>true</code> if and only if the name should be * included in the file list; <code>false</code> otherwise. boolean accept(File dir, String name); } * *我们可以看到,FilenameFilter只是一个接口,所以如果要用list(FilenameFilter filter)方法 *我们必须要实现这样的一个接口。accept()方法会返回一个boolean类型的值,list()方法会根据这个返回值 *来决定是不是要将某个名字添加到返回列表中。所以,我们要在accept()方法中定义好挑选条件,这会用到正则表达式。 * */ //一、采用实现接口的方式 class FileNameFilter1 implements FilenameFilter{ private Pattern pattern; public FileNameFilter1(String regex) { pattern = Pattern.compile(regex); } @Override public boolean accept(File dir, String name) { boolean result = pattern.matcher(name).matches(); return result; } } /* * 二、采用匿名内部类的方式。 * 不用implements的方式来实现接口,但是定义一个静态方法,此静态方法返回一个FilenameFilter对象, * 本来正常的语句是return new FilenameFilter();但是在语句结束之前我说“等一下,我要在这里定义 * 一个类,类的具体实现我用一个大括号括起来”。 */ static class FileNameFilter2{ public static FilenameFilter filter(final String regex){ return new FilenameFilter(){ private Pattern pattern = Pattern.compile(regex); @Override public boolean accept(File dir, String name) { return pattern.matcher(name).matches(); } }; } } @Test public void test2(){ System.out.println("------挑选当前目录下以.开头的文件或文件夹-------"); //1、挑选当前目录下以.开头的文件或文件夹,并且打印出来(创建一个类来实现FilenameFilter接口) File path = new File("."); String[] nameList = path.list(new FileNameFilter1("\\..*")); for(String itemName : nameList){ System.out.println(itemName); } System.out.println("------挑选当前目录下以b开头的文件或文件夹-------"); //2、挑选当前目录下以b开头的文件或文件夹,并且打印出来(使用匿名内部类的方式来实现) File path2 = new File("."); String[] nameList2 = path2.list(FileNameFilter2.filter("b.*")); for(String itemName : nameList2){ System.out.println(itemName); } System.out.println("------挑选当前目录下以s开头的文件或文件夹-------"); //3、将匿名内部类利用到极致 File path3 = new File("."); String[] nameList3 = path3.list(new FilenameFilter(){//其实是在第二种方式的基础上精简过来的。 private Pattern pattern = Pattern.compile("s.*"); @Override public boolean accept(File dir, String name) { return pattern.matcher(name).matches(); } }); for(String itemName : nameList3){ System.out.println(itemName); } } /* * list()和listFiles()方法的区别在于:list()返回的是一个String类型数组,它只是一个数组; * 而listFiles()方法返回的是一个File类的引用,它具有类的所有属性和方法。 * * 下面的前三个方法返回File[]类型,第四个返回static File[]类型。 * 返回类型 : 该路径下所有文件或文件夹的绝对路径(pathname,注意File类型指的是路径,而不是文件) * listFiles() * listFiles(FileFilter filter) * listFiles(FilenameFilter filter) * listRoots() * */ @Test public void test3(){ System.out.println("-----判别当前目录下的文件是否为文件夹----"); //1、列出当前目录下的所有文件和文件夹,保存为File类对象的数组,判别其是否为文件夹 File path = new File("."); File[] files = path.listFiles(); for(File f : files){ System.out.println(f + " ---> is a Directory? " + f.isDirectory()); } System.out.println("-----挑选出当前目录下的所有文件夹----"); //2、挑选出当前目录下的所有文件夹 File path2 = new File("."); File[] files2 = path2.listFiles(new FileFilter(){ @Override public boolean accept(File pathname) { return pathname.isDirectory(); } }); for(File f : files2){ System.out.println(f); } System.out.println("-----挑选出当前目录下的所有以s开头的文件夹----"); //2、挑选出当前目录下的所有以s开头的文件夹 File path3 = new File("."); File[] files3 = path3.listFiles(new FileFilter(){ @Override public boolean accept(File pathname) { Pattern pattern = Pattern.compile("s.*"); return pathname.isDirectory()&&pattern.matcher(pathname.getName()).matches(); } }); for(File f : files3){ System.out.println(f); } System.out.println("-----挑选出当前目录下的所有以.开头的文件夹,并且标明文件属性----"); //3、挑选出当前目录下以.开头的文件或文件夹,并且在其后部标明f/d标明其为文件或文件夹 File path4 = new File("."); File[] files4 = path4.listFiles(new FilenameFilter(){ Pattern pattern = Pattern.compile("\\..*"); @Override public boolean accept(File dir, String name) { return pattern.matcher(name).matches(); } }); for(File f : files4){ String sfd = (f.isFile()) ? "f" : "d"; System.out.println(f.getName() + "---->" + sfd); } }
}