Как мне перебрать файлы в каталоге на Java?

Мне нужно получить список всех файлов в каталоге, включая файлы во всех подкаталогах. Каков стандартный способ выполнения итерации каталогов с Java?

8 ответов

Решение

Ты можешь использовать 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());
        }
    }
}

Обратите внимание, что это чувствительно к StackruErrorкогда дерево глубже, чем может вместить стек JVM. Вы можете вместо этого использовать итеративный подход или хвостовую рекурсию, но это уже другая тема;)

Если вы используете 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, вы можете использовать потоковый интерфейс с 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();
    }
  }

}

Проверьте класс FileUtils в Apache Commons - в частности, iterateFiles:

Позволяет перебирать файлы в данном каталоге (и, необязательно, его подкаталоги).

С помощью 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, если вы не хотите файлы из подкаталогов.

Для 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;
}

Это дерево, поэтому рекурсия - ваш друг: начните с родительского каталога и вызовите метод, чтобы получить массив дочерних файлов. Итерация по дочернему массиву. Если текущее значение является каталогом, передайте его рекурсивному вызову вашего метода. Если нет, обработайте файл листа соответствующим образом.

Как уже отмечалось, это проблема рекурсии. В частности, вы можете посмотреть на

listFiles() 

В Java File API здесь. Возвращает массив всех файлов в каталоге. Используя это вместе с

isDirectory()

посмотреть, нужно ли вам продолжать курс, - это хорошее начало.

Вы также можете неправильно использовать 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;
    }
});

Мне нравится использовать Optional и streams, чтобы получить чистое и понятное решение, я использую приведенный ниже код для перебора каталога. следующие случаи обрабатываются кодом:

  1. обрабатывать случай пустого каталога
  2. Лень

но, как упоминалось другими, вам все равно нужно обращать внимание на 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>

Чтобы добавить ответ @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;
        }
});
Другие вопросы по тегам