File.listFiles 文件过滤器接口 FilenameFilter 和 FileFilter

原创 javaiofile

在操作读取文件的时候,经常会遇到需要过滤某些格式的文件,比如图片或者 jar 包文件,对于这种情况,Java 提供了文件过滤器接口 FilenameFilterFileFilter

FilenameFilter 和 FileFilter 都是用来过滤文件,例如过滤,以 .jpg 或者 .java 结尾的文件,通过看他们的源码:通过使用 File 类中 String[] list(FilenameFilter filter) 或者 public File[] listFiles(FileFilter filter) 方法,把 FilenameFilter 或者 FileFilter 接口对象作为参数传入,通过实现接口里面的 boolean accept(File dir, String name) 或者 boolean accept(File pathname) 方法来过滤出满足条件的文件。

那么他们有什么区别呢?通过下面的源码片段可以看出,FilenameFilter 的 accept 方法接受的参数为待处理文件父目录对象和文件名称字符串,而 FileFilter 的 accept 接受的参数为待处理文件对象。另外 File.list 接口返回的是文件名称字符串数组 String[],所以自然的,只提供了参数为 FilenameFilter 的方法。

下面通过一个假定的需求来展示这两个过滤器的使用:我们做了一个加载器,需要读取文件夹下的驱动文件,驱动文件以 .jar.zip 的后缀形式存在,该文件夹下还有一些说明文档,我们的代码片段就是要读取所有的驱动文件,忽略其它文档。

驱动文件目录下的文件如图所示:

FilenameFilter

看下 FilenameFilter 接口的 accept 原型:

/**
 * Tests if a specified file should be included in a file list.
 *
 * @param   dir    被找到的文件所在的目录
 * @param   name   被找到的文件的文件名
 * @return  `true` if and only if the name should be
 * included in the file list; `false` otherwise.
 */
boolean accept(File dir, String name);

这个方法返回值:当且仅当该文件符合 accept 实现的逻辑时返回 true;否则返回 false。

我们需要做的就是实现 accept 方法,加入我们的实现逻辑。

@Test
public void testFilenameFilter()
{
    File driverDir = new File("E:\\driver");
    File[] drivers = driverDir.listFiles(new FilenameFilter()
    {
        @Override
        public boolean accept(File dir, String name)
        {
            name = name.toLowerCase();
            return name.endsWith(".jar") || name.endsWith(".zip");
        }
    });

    for (File driver : drivers)
    {
        System.out.println(driver.getName());
    }
}

输出过滤后的文件名称:

jtds-1.3.1.jar
mysql-connector-java-5.1.24-bin.jar
ojdbc6.jar
orai18n.jar
pg.zip
xdb6.jar

FileFilter

FileFilter 接口的 accept 原型:

/**
 * Tests whether or not the specified abstract pathname should be
 * included in a pathname list.
 *
 * @param  pathname  被找到文件的 File 对象
 * @return  `true` if and only if `pathname`
 *          should be included
 */
boolean accept(File pathname);

返回值和 FilenameFilter 是一样的,当且仅当该文件符合 accept 实现的逻辑时返回 true;否则返回 false。

我们使用 FileFilter 来重新实现上面的需求。

@Test
public void testFileFilter()
{
    File driverDir = new File("E:\\driver");
    File[] drivers = driverDir.listFiles(new FileFilter()
    {
        @Override
        public boolean accept(File pathname)
        {
            String name = pathname.getName().toLowerCase();
            return name.endsWith(".jar") || name.endsWith(".zip");
        }
    });

    for (File driver : drivers)
    {
        System.out.println(driver.getName());
    }
}

输出结果是一样的:

jtds-1.3.1.jar
mysql-connector-java-5.1.24-bin.jar
ojdbc6.jar
orai18n.jar
pg.zip
xdb6.jar

lambda

JDK 8 为 Java 带来了 lambda 特性,使用我们能够使用更简洁的方式来书写 Java 代码。在源码包中使用 @FunctionalInterface 注解标注的接口都是支持 lambda 实现的,我们也可以使用这个注解来声明自己的 lambda 接口,这不是本文的主题,暂时不表。

FilenameFilterFileFilter 文件过滤器接口也是支持 lambda 的,因为他们的接口声明都有 @FunctionalInterface 注解。

@FunctionalInterface
public interface FilenameFilter {
    boolean accept(File dir, String name);
}

@FunctionalInterface
public interface FileFilter {
    boolean accept(File pathname);
}

我们使用 lambda 的方式来重写上面 FilenameFilter 实现需求的代码:

@Test
public void testFilenameFilter()
{
    File driverDir = new File("E:\\driver");
    File[] drivers = driverDir.listFiles((File dir, String name) ->
    {
        name = name.toLowerCase();
        return name.endsWith(".jar") || name.endsWith(".zip");
    });

    Arrays.asList(drivers).forEach(System.out::println);
}

是不是非常简洁!

关于如何使用 File.list(FilenameFilter) 接口和使用 lambda 重写上面 FileFilter 实现需求的代码,留给读者尝试。

如果觉得这对你有用,请随意赞赏,给与作者支持
评论 0
最新评论