简体   繁体   English

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

[英]How do I iterate through the files in a directory in Java?

I need to get a list of all the files in a directory, including files in all the sub-directories.我需要获取目录中所有文件的列表,包括所有子目录中的文件。 What is the standard way to accomplish directory iteration with Java?用 Java 完成目录迭代的标准方法是什么?

You can use File#isDirectory() to test if the given file (path) is a directory.您可以使用File#isDirectory()来测试给定的文件(路径)是否为目录。 If this is true , then you just call the same method again with its File#listFiles() outcome.如果这是true ,那么您只需使用File#listFiles()结果再次调用相同的方法。 This is called recursion .这称为递归

Here's a basic kickoff example:这是一个基本的开球示例:

package com.stackoverflow.q3154488;

import java.io.File;

public class Demo {

    public static void main(String... args) {
        File dir = new File("/path/to/dir");
        showFiles(dir.listFiles());
    }

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

Note that this is sensitive to StackOverflowError when the tree is deeper than the JVM's stack can hold.请注意,当树比 JVM 的堆栈可以容纳的深度更深时,这对StackOverflowError很敏感。 If you're already on Java 8 or newer, then you'd better use Files#walk() instead which utilizes tail recursion :如果您已经使用 Java 8 或更新版本,那么您最好使用Files#walk()而不是利用尾递归

package com.stackoverflow.q3154488;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class DemoWithJava8 {

    public static void main(String... args) throws Exception {
        Path dir = Paths.get("/path/to/dir");
        Files.walk(dir).forEach(path -> showFile(path.toFile()));
    }

    public static void showFile(File file) {
        if (file.isDirectory()) {
            System.out.println("Directory: " + file.getAbsolutePath());
        } else {
            System.out.println("File: " + file.getAbsolutePath());
        }
    }
}

If you are using Java 1.7, you can use java.nio.file.Files.walkFileTree(...) .如果您使用的是 Java 1.7,则可以使用java.nio.file.Files.walkFileTree(...)

For example:例如:

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();
    }
  }

}

If you are using Java 8, you can use the stream interface with java.nio.file.Files.walk(...) :如果您使用的是 Java 8,您可以使用带有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();
    }
  }

}

Check out the FileUtils class in Apache Commons - specifically iterateFiles :退房的文件实用程序在Apache的百科全书类-特别iterateFiles

Allows iteration over the files in given directory (and optionally its subdirectories).允许迭代给定目录(以及可选的其子目录)中的文件。

Using org.apache.commons.io.FileUtils使用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());            
} 

Use false if you do not want files from sub directories.如果您不想要来自子目录的文件,请使用 false。

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

Example taken from the Javadoc:取自 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;
}

It's a tree, so recursion is your friend: start with the parent directory and call the method to get an array of child Files.它是一棵树,因此递归是您的朋友:从父目录开始并调用该方法以获取子文件数组。 Iterate through the child array.遍历子数组。 If the current value is a directory, pass it to a recursive call of your method.如果当前值是一个目录,则将其传递给您的方法的递归调用。 If not, process the leaf file appropriately.如果没有,请适当处理叶文件。

As noted, this is a recursion problem.如前所述,这是一个递归问题。 In particular, you may want to look at特别是,你可能想看看

listFiles() 

In the java File API here .此处的 java File API 中。 It returns an array of all the files in a directory.它返回一个目录中所有文件的数组。 Using this along with与此一起使用

isDirectory()

to see if you need to recurse further is a good start.看看你是否需要进一步递归是一个好的开始。

You can also misuse File.list(FilenameFilter) (and variants) for file traversal.您还可以滥用 File.list(FilenameFilter)(和变体)进行文件遍历。 Short code and works in early java versions, eg:短代码并适用于早期的 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;
    }
});

To add with @msandiford answer, as most of the times when a file tree is walked u may want to execute a function as a directory or any particular file is visited.要添加@msandiford 答案,因为大多数情况下遍历文件树时,您可能希望将函数作为目录或访问任何特定文件来执行。 If u are reluctant to using streams.如果你不愿意使用流。 The following methods overridden can be implemented可以实现以下重写的方法

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;
        }
});

I like to use Optional and streams to have a net and clear solution, i use the below code to iterate over a directory.我喜欢使用Optional来获得清晰的解决方案,我使用以下代码遍历目录。 the below cases are handled by the code:以下情况由代码处理:

  1. handle the case of empty directory处理空目录的情况
  2. Laziness懒惰

but as mentioned by others, you still have to pay attention for outOfMemory in case you have huge folders但正如其他人提到的,如果你有巨大的文件夹,你仍然需要注意 outOfMemory

    File directoryFile = new File("put your path here");
    Stream<File> files = Optional.ofNullable(directoryFile// directoryFile
                                                          .listFiles(File::isDirectory)) // filter only directories(change with null if you don't need to filter)
                                 .stream()
                                 .flatMap(Arrays::stream);// flatmap from Stream<File[]> to Stream<File>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM