如何遍历Java目录中的文件?


175

我需要获取目录中所有文件的列表,包括所有子目录中的文件。用Java完成目录迭代的标准方法是什么?

Answers:


207

您可以File#isDirectory()用来测试给定的文件(路径)是否为目录。如果是true,则只需再次调用同一个方法及其File#listFiles()结果即可。这称为递归

这是一个基本的启动示例。

public static void main(String... args) {
    File[] files = new File("C:/").listFiles();
    showFiles(files);
}

public static void showFiles(File[] files) {
    for (File file : files) {
        if (file.isDirectory()) {
            System.out.println("Directory: " + file.getName());
            showFiles(file.listFiles()); // Calls same method again.
        } else {
            System.out.println("File: " + file.getName());
        }
    }
}

请注意,这StackOverflowError对于树的深度超过JVM堆栈可以容纳的深度很敏感。您可能要使用迭代方法或尾递归,但这是另一个主题;)


感谢Balus,关于一般猜测有多深?
詹姆斯

10
取决于JVM的内存设置。但是通常大约几千。如果您认为自己可能会遇到过这样的目录,请不要使用递归。
Mike Baranczak 2010年

4
这是易受NullPointerException时调用的文件系统的变化isDirectory,并listFiles为可能发生,如果System.out.println块或者你只是得到真正倒霉。检查的输出listFiles不为null将解决该竞争条件。
Mike Samuel

1
@BoratSagdiyev,不使用旧的Java文件API,但是如果您使用的是现代JVM,则java.nio.file.DirectoryStream允许您在目录上进行迭代,并且可以实现为具有较小的内存占用,但是唯一可以确定的方法是监视特定平台上的内存使用情况。
Mike Samuel

1
“ C:\\”文件夹不是示例的最佳选择)
Vyacheslav

86

如果您使用的是Java 1.7,则可以使用java.nio.file.Files.walkFileTree(...)

例如:

public class WalkFileTreeExample {

  public static void main(String[] args) {
    Path p = Paths.get("/usr");
    FileVisitor<Path> fv = new SimpleFileVisitor<Path>() {
      @Override
      public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
          throws IOException {
        System.out.println(file);
        return FileVisitResult.CONTINUE;
      }
    };

    try {
      Files.walkFileTree(p, fv);
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

}

如果您使用的是Java 8,则可以将stream接口用于java.nio.file.Files.walk(...)

public class WalkFileTreeExample {

  public static void main(String[] args) {
    try (Stream<Path> paths = Files.walk(Paths.get("/usr"))) {
      paths.forEach(System.out::println);
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

}

1
流到新目录并执行功能时,流中是否有办法放置检查点?
Raghu DV

28

退房的文件实用程序在Apache的百科全书类-特别iterateFiles

允许迭代给定目录(及其子目录)中的文件。


5
这个API并不是真正的流式传输(如果您关心内存的使用),它首先生成一个集合,然后才在其上返回一个迭代器:return listFiles(directory,fileFilter,dirFilter).iterator();
Gili Nachum

Java 1.6的不错选择。
David I.

同意@GiliNachum。Apache的FileUtils首先收集所有文件并为其提供迭代器。如果您有大量文件,则对资源有害。
Bogdan Samondros

8

对于Java 7+,还有https://docs.oracle.com/javase/7/docs/api/java/nio/file/DirectoryStream.html

取自Javadoc的示例:

List<Path> listSourceFiles(Path dir) throws IOException {
   List<Path> result = new ArrayList<>();
   try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, "*.{c,h,cpp,hpp,java}")) {
       for (Path entry: stream) {
           result.add(entry);
       }
   } catch (DirectoryIteratorException ex) {
       // I/O error encounted during the iteration, the cause is an IOException
       throw ex.getCause();
   }
   return result;
}

8

使用 org.apache.commons.io.FileUtils

File file = new File("F:/Lines");       
Collection<File> files = FileUtils.listFiles(file, null, true);     
for(File file2 : files){
    System.out.println(file2.getName());            
} 

如果您不希望子目录中的文件,请使用false。


3

它是一棵树,因此递归是您的朋友:从父目录开始,并调用该方法以获取子文件数组。遍历子数组。如果当前值为目录,则将其传递给您的方法的递归调用。如果不是,请适当处理叶子文件。


2

如前所述,这是递归问题。特别是,您可能要看一下

listFiles() 

在java File API 此处。它返回目录中所有文件的数组。结合使用

isDirectory()

看看是否需要进一步递归是一个好的开始。


链接可能有用,因为答案中的链接已断开。
Donglecow

0

要添加@msandiford答案,在大多数情况下,当遍历文件树时,您可能希望执行目录或访问任何特定文件的功能。如果您不愿使用流。可以实现以下方法

Files.walkFileTree(Paths.get(Krawl.INDEXPATH), EnumSet.of(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE,
    new SimpleFileVisitor<Path>() {
        @Override
        public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
                throws IOException {
                // Do someting before directory visit
                return FileVisitResult.CONTINUE;
        }
        @Override
        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
                throws IOException {
                // Do something when a file is visited
                return FileVisitResult.CONTINUE;
        }
        @Override
        public FileVisitResult postVisitDirectory(Path dir, IOException exc)
                throws IOException {
                // Do Something after directory visit 
                return FileVisitResult.CONTINUE;
        }
});

0

您也可以将File.list(FilenameFilter)(和变体)误用于文件遍历。简短的代码,可以在早期的Java版本中使用,例如:

// list files in dir
new File(dir).list(new FilenameFilter() {
    public boolean accept(File dir, String name) {
        String file = dir.getAbsolutePath() + File.separator + name;
        System.out.println(file);
        return false;
    }
});
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.