2014-02-08 37 views
17

我想列出递归使用Java 8递归流

的Java 8提供了一个listFiles方法返回所有的文件和目录,但没有递归我的计算机上的所有文件。我如何使用它来获得文件的完整递归列表(不使用变异集合)?

我尝试下面的代码,但它只是深藏一层:

static Function<Path, Stream<Path>> listFiles = p -> { 
    if (p.toFile().isDirectory()) { 
     try { return Files.list(p); } 
     catch (Exception e) { return Stream.empty(); } 
    } else { 
     return Stream.of(p); 
    } 
}; 

public static void main(String[] args) throws IOException { 
    Path root = Paths.get("C:/temp/"); 
    Files.list(root).flatMap(listFiles).forEach(System.out::println); 
} 

而且使用return Files.list(p).flatMap(listFiles);不编译(不知道为什么)...

注:我没兴趣在涉及FileVisitors或外部库的解决方案中。

+1

'Files.walkFileTree'?或者,你真的只是想使用递归流吗? :-) –

+1

@StuartMarks是的,我只是想使用递归流! walkFileTree非常详细,所以我试图找到一个“一行”。 – assylias

+1

哎呀,我的意思是'Files.walk'。它需要一个路径并返回一个流。 –

回答

17

通过递归遍历文件系统来生成路径流的新API是Files.walk

如果你真的想递归地产生流(不一定是走在文件树,但我会继续使用,作为一个例子),它可能是更直接一点的使用方法引用来完成递归:

class RecursiveStream { 
    static Stream<Path> listFiles(Path path) { 
     if (Files.isDirectory(path)) { 
      try { return Files.list(path).flatMap(RecursiveStream::listFiles); } 
      catch (Exception e) { return Stream.empty(); } 
     } else { 
      return Stream.of(path); 
     } 
    } 

    public static void main(String[] args) { 
     listFiles(Paths.get(".")).forEach(System.out::println); 
    } 
} 

方法引用对于将具有相同“形状”(参数和返回类型)的命名方法作为功能接口适配到该功能接口非常有用。这也避免了将lambda存储在实例或静态变量中并递归调用自身的潜在初始化循环。

3

显然不可能通过方法引用来引用该函数定义中的函数,但它可以与lambda函数一起使用。

所以在函数中,return Files.list(p).flatMap(listFiles);不能编译,但return Files.list(p).flatMap(q -> listFiles.apply(q));呢。

打印在递归的指定文件夹中的所有文件:

static final Function<Path, Stream<Path>> listFiles = p -> { 
    if (p.toFile().isDirectory()) { 
     try { return Files.list(p).flatMap(q -> listFiles.apply(q)); } 
     catch (Exception e) { return Stream.empty(); } 
    } else { 
     return Stream.of(p); 
    } 
}; 

public static void main(String[] args) throws IOException { 
    Path root = Paths.get("C:/temp/"); 
    Files.list(root).flatMap(listFiles).forEach(System.out::println); 
} 

但正如指出的那样,这是不必要的:

Files.walk(root).forEach(System.out::println); 

做同样的事情...

+0

它不能在JDK 8 b127上编译:'不能在定义之前引用一个字段。' – nobeh

+0

它编译在b128上 – assylias

+0

只需注意:这依赖于'listFiles '作为示例中显示的静态字段,并且在其他情况下不起作用。即使如此,使用最新的JDK,除非我首先将字段初始化为'null',然后转向并用lambda重新初始化它,否则我无法编译它。当然,这一切似乎都很臭。 – jkschneider