NIO.2中如何列举和过滤目录的内容

一直到Java7发布之前,Java在列举目录的内容方面一直没有什么太大的变化。但是,NIO.2引入了一种新的列举目录内容方式,因此值得来说一下。NIO.2的一个重大的改进是可以在一个方法调用中同时使用列举和过滤。
这个给大多数对文件系统有列举/过滤需求的应用提供了一种优雅的解决方案。

列出根目录

除非是使用相对路径,很多时候我们都要知道我们应用所处的环境,因此可能要使用绝对路径。因为文件系统通常是有等级结构的,至少会有一个根目录,因此为了正确的定位文件和目录,我们要能够列出所有的根目录。我们可以用FileSystem实例的getRootDirectories()方法来做这个事情,它跟Java6的File.listRoots()的功能是一样的。

Iterable<Path> it = FileSystems.getDefault().getRootDirectories();
 
System.out.println("Root file system locations: " + Sets.newHashSet(it));

注意:Sets类不是JDK的一部分,而是来自Google的Gava库。在这里使用它仅仅是为了方便的获取根目录的格式化的字符串表示。

输出结果:

Root file system locations: C:\, D:\, E:\, F:\, G:\, H:\, I:\, 

列举和过滤目录内容

使用文件系统最常用的工作就是列举或者是过滤给定目录下面的文件。我们可能需要对文件进行修改、分析或者是简单的列举,无论是哪一种原因,java.nio.file.Files类都是我们坚强的后盾。它提供了返回DirectoryStream的newDirectoryStream()的三种重载方法,可以用来迭代目录下面的文件。这里我们看到当前版本IO库跟之前版本(返回简单的数组)一个很明显的防止空指针的区别。下面的例子展示了列出给定目录下面的内容是多么的简单:

Path directoryPath = Paths.get("C:", "Program Files/Java/jdk1.7.0_40/src/java/nio/file");
if (Files.isDirectory(directoryPath)) {
    try (DirectoryStream<Path> stream = Files.newDirectoryStream(directoryPath)) {
        for (Path path : stream) {
            System.out.println(path);
        }
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

请注意,使用isDirectory()方法可以防止NotDirectoryException。同时也要注意try-with-resources结构的使用,DirectoryStream同时是AutoCloseable和Closeable(也就是说在特定时候是需要手动关闭的),因此try-with-resources就派上用场了。上面代码的输出结果:

...
C:\Program Files\Java\jdk1.7.0_40\src\java\nio\file\CopyOption.java
C:\Program Files\Java\jdk1.7.0_40\src\java\nio\file\DirectoryIteratorException.java
C:\Program Files\Java\jdk1.7.0_40\src\java\nio\file\DirectoryNotEmptyException.java
C:\Program Files\Java\jdk1.7.0_40\src\java\nio\file\DirectoryStream.java
C:\Program Files\Java\jdk1.7.0_40\src\java\nio\file\FileAlreadyExistsException.java
C:\Program Files\Java\jdk1.7.0_40\src\java\nio\file\Files.java
C:\Program Files\Java\jdk1.7.0_40\src\java\nio\file\FileStore.java
C:\Program Files\Java\jdk1.7.0_40\src\java\nio\file\FileSystem.java
C:\Program Files\Java\jdk1.7.0_40\src\java\nio\file\FileSystemAlreadyExistsException.java
...

为了确保DirectoryStream的通用性,我们可以使用两种基本的方法做过滤:

newDirectoryStream(Path dir, String glob)
- 用GLOB做过滤

newDirectoryStream (Path dir,DirectoryStream.Filterfilter)
- 用DirectoryStream.Filter做过滤

用GLOB模式做过滤

首先我们要知道GLOB是什么。GLOB模式是遵守特定语法规则的主要用来做匹配的字符串表达式。可以参考下面的文章获取更多关于GLOB和GLOB语法的信息。当使用GLOB做过滤的时候,Files类给我们提供了一种很简单的方式。让我们看下下面的例子。

Path directoryPath = Paths.get("C:", "Program Files/Java/jdk1.7.0_40/src/java/nio/file");
if (Files.isDirectory(directoryPath)) {
    try (DirectoryStream<Path> stream = Files.newDirectoryStream(directoryPath, "File*Exception*")) {
        for (Path path : stream) {
            System.out.println(path);
        }
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

输出结果:

C:\Program Files\Java\jdk1.7.0_40\src\java\nio\file\FileAlreadyExistsException.java
C:\Program Files\Java\jdk1.7.0_40\src\java\nio\file\FileSystemAlreadyExistsException.java
C:\Program Files\Java\jdk1.7.0_40\src\java\nio\file\FileSystemException.java
C:\Program Files\Java\jdk1.7.0_40\src\java\nio\file\FileSystemLoopException.java
C:\Program Files\Java\jdk1.7.0_40\src\java\nio\file\FileSystemNotFoundException.java

用DirectoryStream.Filter做过滤

当我们的工作不仅仅是简单的文件名匹配而是更复杂的过滤操作的时候,我们需要实现DirectoryStream.Filter接口。这是可用的最强大的过滤选项,因为我们可以有方式来访问应用程序其他部分,甚至使用第三方类库。下面的例子展示了这样的使用两个过滤条件的情况:

  • 文件的大小必须是偶数
  • 执行时间的毫秒数必须是偶数
Path directoryPath = Paths.get("C:", "Program Files/Java/jdk1.7.0_40/src/java/nio/file");
DirectoryStream.Filter<Path> filter = new Filter<Path>() {
    @Override
    public boolean accept(Path entry) throws IOException {
        long size = Files.readAttributes(entry, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS).size();
        long milis = new Date().getTime();
        boolean isSizeEvenNumber = size % 2 == 0;
        boolean isTheTimeRight = milis % 2 == 0;
        return isTheTimeRight && isSizeEvenNumber;
    }
};
if (Files.isDirectory(directoryPath)) {
    try (DirectoryStream<Path> stream = Files.newDirectoryStream(directoryPath, filter)) {
        for (Path path : stream) {
            System.out.println(path);
        }
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

输出结果:

C:\Program Files\Java\jdk1.7.0_40\src\java\nio\file\DirectoryStream.java
C:\Program Files\Java\jdk1.7.0_40\src\java\nio\file\FileAlreadyExistsException.java
C:\Program Files\Java\jdk1.7.0_40\src\java\nio\file\Files.java
C:\Program Files\Java\jdk1.7.0_40\src\java\nio\file\NotDirectoryException.java
C:\Program Files\Java\jdk1.7.0_40\src\java\nio\file\NotLinkException.java
C:\Program Files\Java\jdk1.7.0_40\src\java\nio\file\package-info.java
C:\Program Files\Java\jdk1.7.0_40\src\java\nio\file\WatchEvent.java
C:\Program Files\Java\jdk1.7.0_40\src\java\nio\file\WatchService.java

需要注意,根据使用的过滤条件过滤出来的文件每次执行都可能是不一样的。

引自在NIO.2中列举和过滤目录内容,来自我们的JCG合作伙伴Jakub Stas在Jakub Stas的博客。

猜你可能也会喜欢:

Java 7: 使用NIO.2做文件过滤-第一部分

Java 7: 使用NIO.2做文件过滤-第二部分

Java 7: 使用NIO.2做文件过滤-第三部分

原文链接: javacodegeeks 翻译: ImportNew.com - miracle1919
译文链接: http://www.importnew.com/12163.html
[ 转载请保留原文出处、译者和译文链接。]



相关文章

发表评论

Comment form

(*) 表示必填项

还没有评论。

跳到底部
返回顶部