【问题标题】:Java, List only subdirectories from a directory, not filesJava,仅列出目录中的子目录,而不是文件
【发布时间】:2011-02-26 05:23:07
【问题描述】:

在 Java 中,如何仅列出目录中的子目录?

我想使用 java.io.File 功能,Java 中最好的方法是什么?

【问题讨论】:

    标签: java file


    【解决方案1】:

    您可以使用File 类来列出目录。

    File file = new File("/path/to/directory");
    String[] directories = file.list(new FilenameFilter() {
      @Override
      public boolean accept(File current, String name) {
        return new File(current, name).isDirectory();
      }
    });
    System.out.println(Arrays.toString(directories));
    

    更新

    作者对这篇文章的评论想要一个更快的方法,在这里进行很好的讨论: How to retrieve a list of directories QUICKLY in Java?

    基本上:

    1. 如果您控制文件结构,我会尽量避免陷入这种情况。
    2. 在 Java NIO.2 中,您可以使用目录函数返回一个迭代器以实现更大的缩放。目录流类是一个对象,您可以使用它来遍历目录中的条目。

    【讨论】:

    • 您好,感谢您的回复。但我不必遍历目录中的所有项目。我必须直接从目录中列出子目录。因为我有很多文件,但目录中只有几个子目录,所以检查 isDirectory() 非常耗时。请以另一种方式回复我。
    • 我更新了我的帖子,特别是看看 Jon Skeet 对这个问题的评论。并且自 Java NIO 2 以来的 NIO 响应具有用于返回目录流的目录函数的迭代器。
    • 你指的是什么飞碟评论?这里表现更好的答案是什么?
    【解决方案2】:

    一个非常简单的 Java 8 解决方案:

    File[] directories = new File("/your/path/").listFiles(File::isDirectory);
    

    这相当于使用 FileFilter(也适用于较旧的 Java):

    File[] directories = new File("/your/path/").listFiles(new FileFilter() {
        @Override
        public boolean accept(File file) {
            return file.isDirectory();
        }
    });
    

    【讨论】:

    • 双冒号::在这种情况下如何工作?
    • 我注意到没有其他答案使用 FileFilter 所以我添加了等效版本而不使用方法引用。有关方法参考的更多信息,请参阅此SO question 或此article
    • 这是获取子目录还是只获取 /your/path/ 下的目录?
    • :: 从类 File 发送函数 isDirectory 作为参数
    【解决方案3】:

    @Mohamed Mansour 你快到了......你使用的“dir”参数实际上是当前路径,所以它总是会返回 true。为了查看子目录是否是子目录,您需要测试该子目录。

    File file = new File("/path/to/directory");
    String[] directories = file.list(new FilenameFilter() {
      @Override
      public boolean accept(File current, String name) {
        return new File(current, name).isDirectory();
      }
    });
    System.out.println(Arrays.toString(directories));
    

    【讨论】:

      【解决方案4】:

      如果您对使用 Java 7 和 NIO.2 的解决方案感兴趣,可以这样:

      private static class DirectoriesFilter implements Filter<Path> {
          @Override
          public boolean accept(Path entry) throws IOException {
              return Files.isDirectory(entry);
          }
      }
      
      try (DirectoryStream<Path> ds = Files.newDirectoryStream(FileSystems.getDefault().getPath(root), new DirectoriesFilter())) {
              for (Path p : ds) {
                  System.out.println(p.getFileName());
              }
          } catch (IOException e) {
              e.printStackTrace();
          }
      

      【讨论】:

        【解决方案5】:
        ArrayList<File> directories = new ArrayList<File>(
            Arrays.asList(
                new File("your/path/").listFiles(File::isDirectory)
            )
        );
        

        【讨论】:

        • 嗨,欢迎来到 *!你能详细说明你的答案吗?比如解释代码 sn-ps 中有趣的部分或链接到文档以供进一步阅读?
        • 这应该是正确的答案,因为它提供了具有完整规范路径的 File 对象。这可能是旧的,但值得指出这一点
        【解决方案6】:

        我想使用 java.io.File 功能,

        2012 年(问题日期)是的,不是今天。 java.nio API 必须满足此类要求。

        有这么多答案很糟糕,但不是我会使用的简单方法Files.walk().filter().collect()

        全球有两种可能的方法:

        1)Files.walk(Path start, ) 没有 maxDepth 限制,而

        2)Files.walk(Path start, int maxDepth, FileVisitOption... options)允许设置。

        如果不指定任何深度限制,它将给出:

        Path directory = Paths.get("/foo/bar");
        
        try {
            List<Path> directories =
                    Files.walk(directory)
                         .filter(Files::isDirectory)
                         .collect(Collectors.toList());
        } catch (IOException e) {
            // process exception
        }
        

        如果出于遗留原因,您需要获取File 的列表,您可以在收集之前添加map(Path::toFile) 操作:

        Path directory = Paths.get("/foo/bar");
        
        try {
            List<File> directories =
                    Files.walk(directory)
                         .filter(Files::isDirectory)
                         .map(Path::toFile)
                         .collect(Collectors.toList());
        } catch (IOException e) {
            // process exception
        }
        

        【讨论】:

        • 还有Files.list(Path),大概和Files.walk(Path,1)一样。
        • @David L 实际上,如果我们不想递归地迭代文件夹,Files.list(Path) 是一个不错的选择。要递归地迭代文件夹,walk() 更适合。
        【解决方案7】:

        对于那些也对 Java 7 和 NIO 感兴趣的人,@voo's answer above 有一个替代解决方案。我们可以使用调用 Files.find()try-with-resources 和用于过滤目录的 lambda 函数。

        import java.io.IOException;
        import java.nio.file.Files;
        import java.nio.file.Path;
        import java.nio.file.Paths;
        import java.util.stream.Stream;
        
        
        final Path directory = Paths.get("/path/to/folder");
        
        try (Stream<Path> paths = Files.find(directory, Integer.MAX_VALUE, (path, attributes) -> attributes.isDirectory())) {
            paths.forEach(System.out::println);
        } catch (IOException e) {
            ...
        }
        

        我们甚至可以通过更改 lambda 函数按名称过滤目录:

        (path, attributes) -> attributes.isDirectory() && path.toString().contains("test")
        

        或按日期:

        final long now = System.currentTimeMillis();
        final long yesterday = new Date(now - 24 * 60 * 60 * 1000L).getTime();
        
        // modified in the last 24 hours
        (path, attributes) -> attributes.isDirectory() && attributes.lastModifiedTime().toMillis() > yesterday
        

        【讨论】:

          【解决方案8】:

          这将逐字列出(即打印)所有子目录。它基本上是一种循环,您不需要将中间的项目存储到列表中。这是最有可能需要的,所以我把它留在这里。

          Path directory = Paths.get("D:\\directory\\to\\list");
          
          Files.walk(directory, 1).filter(entry -> !entry.equals(directory))
              .filter(Files::isDirectory).forEach(subdirectory ->
          {
              // do whatever you want with the subdirectories
              System.out.println(subdirectory.getFileName());
          });
          

          【讨论】:

            【解决方案9】:

            答案列表中缺少对我有用的解决方案。因此,我在此处发布此解决方案:

            File[]dirs = new File("/mypath/mydir/").listFiles((FileFilter)FileFilterUtils.directoryFileFilter());
            

            这里我使用了来自 Apache commons-io-2.2.jar 的 org.apache.commons.io.filefilter.FileFilterUtils。其文档可在此处获得:https://commons.apache.org/proper/commons-io/javadocs/api-2.2/org/apache/commons/io/filefilter/FileFilterUtils.html

            【讨论】:

              【解决方案10】:
                  File files = new File("src");
                  // src is folder name...
                  //This will return the list of the subDirectories
                  List<File> subDirectories = Arrays.stream(files.listFiles()).filter(File::isDirectory).collect(Collectors.toList());
              // this will print all the sub directories
              Arrays.stream(files.listFiles()).filter(File::isDirectory).forEach(System.out::println);
              

              【讨论】:

                【解决方案11】:

                给定一个起始目录为String

                1. 创建一个以String 路径为参数的方法。方法中:
                2. 根据起始目录新建File对象
                3. 使用listFiles方法获取当前目录下的文件数组
                4. 遍历文件数组
                  1. 如果是文件,继续循环
                  2. 如果是目录,则在这个新目录路径上打印出名称和递归

                【讨论】:

                • 您好,感谢您的回复。但我不必遍历目录中的所有项目。我必须直接从目录中列出子目录。因为我有很多文件,而目录中只有很少的子目录,所以检查 isDirectory() 非常耗时。请以另一种方式回复我。
                【解决方案12】:

                这是我的代码的解决方案。我只是做了一点更改from first answer。这将仅逐行列出所需目录中的所有文件夹:

                try {
                            File file = new File("D:\\admir\\MyBookLibrary");
                            String[] directories = file.list(new FilenameFilter() {
                              @Override
                              public boolean accept(File current, String name) {
                                return new File(current, name).isDirectory();
                              }
                            });
                            for(int i = 0;i < directories.length;i++) {
                                if(directories[i] != null) {
                                    System.out.println(Arrays.asList(directories[i]));
                
                                }
                            }
                        }catch(Exception e) {
                            System.err.println("Error!");
                        }
                

                【讨论】:

                  【解决方案13】:

                  您可以使用 JAVA 7 Files api

                  Path myDirectoryPath = Paths.get("path to my directory");
                  List<Path> subDirectories = Files.find(
                                      myDirectoryPath ,
                                      Integer.MAX_VALUE,
                                      (filePath, fileAttr) -> fileAttr.isDirectory() && !filePath.equals(myDirectoryPath )
                              ).collect(Collectors.toList());
                  

                  如果你想要一个特定的值,你可以在收集数据之前用你想要的值调用 map。

                  【讨论】: