Bagaimana saya mengulangi file dalam direktori di Java?


175

Saya perlu mendapatkan daftar semua file dalam direktori, termasuk file di semua sub-direktori. Apa cara standar untuk menyelesaikan iterasi direktori dengan Java?

Jawaban:


207

Anda dapat menggunakan File#isDirectory()untuk menguji apakah file (path) yang diberikan adalah direktori. Jika ini true, maka Anda cukup memanggil metode yang sama lagi dengan File#listFiles()hasilnya. Ini disebut rekursi .

Inilah contoh dasar kickoff.

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

Perhatikan bahwa ini sensitif StackOverflowErrorketika pohon lebih dalam dari yang bisa ditumpuk oleh JVM. Anda mungkin ingin menggunakan pendekatan berulang atau rekursi ekor sebagai gantinya, tapi itu subjek lain;)


terima kasih Balus, ada ide tentang seberapa dalam itu mungkin sebagai tebakan umum?
James

10
Tergantung pada pengaturan memori JVM Anda. Tetapi umumnya sekitar beberapa ribu. Jika Anda merasa pernah mengalami direktori seperti itu, maka jangan gunakan rekursi.
Mike Baranczak

4
Ini rentan terhadap NullPointerExceptionketika sistem file berubah antara panggilan ke isDirectorydan listFilesseperti yang mungkin terjadi jika System.out.printlnblok atau Anda hanya benar-benar beruntung. Memeriksa bahwa output listFilesbukan nol akan menyelesaikan kondisi balapan itu.
Mike Samuel

1
@ Boratagdiyev, Tidak menggunakan API file Java yang lama, tetapi jika Anda menggunakan JVM modern maka java.nio.file.DirectoryStreammemungkinkan Anda untuk beralih ke direktori, dan dapat diimplementasikan untuk memiliki jejak memori yang kecil tetapi satu-satunya cara untuk memastikannya adalah untuk memantau penggunaan memori pada platform tertentu.
Mike Samuel

1
"C: \\" folder bukan pilihan terbaik dari contoh)
Vyacheslav

86

Jika Anda menggunakan Java 1.7, Anda dapat menggunakan java.nio.file.Files.walkFileTree(...).

Sebagai contoh:

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

}

Jika Anda menggunakan Java 8, Anda dapat menggunakan antarmuka stream dengan 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
apakah ada cara dengan stream untuk menempatkan pos pemeriksaan ketika direktori baru berjalan dan menjalankan suatu fungsi?
Raghu DV

28

Lihat kelas FileUtils di Apache Commons - khususnya iterateFiles :

Mengizinkan pengulangan atas file dalam direktori yang diberikan (dan juga subdirektori opsional).


5
API ini tidak benar-benar streaming (jika Anda peduli tentang penggunaan mem), ia pertama-tama menghasilkan koleksi, hanya kemudian mengembalikan iterator di atasnya: return listFiles (direktori, fileFilter, dirFilter) .iterator ();
Gili Nachum

Pilihan yang bagus untuk Java 1.6.
David I.

Setuju dengan @GiliNachum. FileUtils oleh Apache pertama mengumpulkan semua file dan memberikan iterator untuk mereka. Ini berbahaya bagi sumber daya jika Anda memiliki banyak file.
Bogdan Samondros

8

Untuk Java 7+, ada juga https://docs.oracle.com/javase/7/docs/api/java/nio/file/DirectoryStream.html

Contoh yang diambil dari 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

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

Gunakan false jika Anda tidak ingin file dari sub direktori.


3

Ini pohon, jadi rekursi adalah teman Anda: mulailah dengan direktori induk dan panggil metode untuk mendapatkan array File anak. Iterate melalui array anak. Jika nilai saat ini adalah direktori, berikan kepada panggilan metode Anda secara rekursif. Jika tidak, proses file daun dengan tepat.


2

Sebagaimana dicatat, ini adalah masalah rekursi. Secara khusus, Anda mungkin ingin melihatnya

listFiles() 

Di java File API di sini . Ini mengembalikan array dari semua file dalam direktori. Menggunakan ini bersama dengan

isDirectory()

untuk melihat apakah Anda perlu berulang lagi adalah awal yang baik.


Tautan ini mungkin berguna karena yang ada dalam jawaban rusak.
Donglecow

0

Untuk menambahkan dengan @msandiford jawab, karena sebagian besar waktu ketika pohon file berjalan Anda mungkin ingin menjalankan fungsi sebagai direktori atau file tertentu dikunjungi. Jika Anda enggan menggunakan stream. Metode berikut yang ditimpa dapat diimplementasikan

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

Anda juga dapat menyalahgunakan File.list (FilenameFilter) (dan varian) untuk traversal file. Kode pendek dan berfungsi dalam versi java awal, misalnya:

// 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;
    }
});
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.