Java, Cantumkan hanya subdirektori dari direktori, bukan file

100

Di Java, Bagaimana cara mencantumkan hanya subdirektori dari direktori?

Saya ingin menggunakan fungsionalitas java.io.File, apa metode terbaik di Java untuk melakukan ini?

Lokesh Paunikar
sumber

Jawaban:

141

Anda dapat menggunakan kelas File untuk mendaftar direktori.

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

Memperbarui

Komentar dari penulis pada posting ini menginginkan cara yang lebih cepat, diskusi hebat di sini: Bagaimana cara mengambil daftar direktori CEPAT di Java?

Pada dasarnya:

  1. Jika Anda mengontrol struktur file, saya akan mencoba menghindari situasi itu.
  2. Di Java NIO.2, Anda dapat menggunakan fungsi direktori untuk mengembalikan iterator untuk memungkinkan penskalaan yang lebih besar. Kelas aliran direktori adalah objek yang dapat Anda gunakan untuk mengulang entri dalam direktori.
Mohamed Mansour
sumber
hai, terima kasih atas balasannya. Tapi saya tidak perlu mengulang semua item dalam direktori. Saya harus mendaftar langsung subdirektori dari direktori. B'coz Saya punya banyak file dan hanya sedikit subdirektori di direktori jadi, memeriksa isDirectory () memakan waktu. tolong balas saya dengan cara lain.
Lokesh Paunikar
Saya memperbarui posting saya, khususnya, lihat komentar Jon Skeet tentang pertanyaan itu. Dan respon NIO karena Java NIO 2 memiliki iterator untuk fungsi direktori yang mengembalikan aliran direktori.
Mohamed Mansour
Apa komentar Skeet yang Anda maksud? Apa jawaban yang berkinerja lebih baik di sini?
Stealth Rabbi
107

Solusi Java 8 yang sangat sederhana:

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

Ini setara dengan menggunakan FileFilter (bekerja dengan Java yang lebih lama juga):

File[] directories = new File("/your/path/").listFiles(new FileFilter() {
    @Override
    public boolean accept(File file) {
        return file.isDirectory();
    }
});
headsvk.dll
sumber
4
Bagaimana cara ::kerja titik dua ganda dalam hal ini?
snickers10m
Saya perhatikan bahwa tidak ada jawaban lain yang menggunakan FileFilter jadi saya menambahkan versi yang setara tanpa menggunakan referensi metode. Untuk informasi lebih lanjut tentang referensi metode, lihat pertanyaan SO atau artikel ini .
headsvk
apakah ini mendapatkan subdirektori atau hanya direktori langsung di bawah / your / path /?
amadain
@amadain tidak ada rekursi seperti yang diharapkan docs.oracle.com/javase/7/docs/api/java/io/File.html#listFiles ()
headsvk
14

@Mohamed Mansour Anda hampir sampai ... argumen "dir" dari yang Anda gunakan sebenarnya adalah jalur saat ini, jadi akan selalu mengembalikan nilai true. Untuk melihat apakah anak itu subdirektori atau tidak, Anda perlu menguji anak itu.

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));
Javier Buzzi
sumber
7

Jika Anda tertarik dengan solusi yang menggunakan Java 7 dan NIO.2, itu bisa seperti ini:

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();
    }
voo
sumber
3
ArrayList<File> directories = new ArrayList<File>(
    Arrays.asList(
        new File("your/path/").listFiles(File::isDirectory)
    )
);
bcangas97
sumber
Hai, dan selamat datang di StackOverflow! Bisakah Anda menjelaskan sedikit tentang jawaban Anda? Seperti menjelaskan bagian menarik dari cuplikan kode Anda atau menautkan ke dokumentasi untuk bacaan lebih lanjut?
Richard-Degenne
Ini harus menjadi jawaban yang benar karena menyediakan objek File dengan Jalur Kanonis lengkap. Ini mungkin sudah tua tetapi perlu ditunjukkan
Jero Dungog
2

Bagi yang juga tertarik dengan Java 7 dan NIO, ada solusi alternatif jawaban @ voo di atas . Kita bisa menggunakan try-with-resources yang memanggil Files.find()dan fungsi lambda yang digunakan untuk memfilter direktori.

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) {
    ...
}

Kami bahkan dapat memfilter direktori berdasarkan nama dengan mengubah fungsi lambda:

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

atau berdasarkan tanggal:

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
HugoTeixeira
sumber
2

Saya ingin menggunakan fungsionalitas java.io.File,

Pada 2012 (tanggal pertanyaan) ya, bukan hari ini. java.nioAPI harus diutamakan untuk persyaratan seperti itu.

Mengerikan dengan begitu banyak jawaban, tetapi bukan cara sederhana yang akan saya gunakan Files.walk().filter().collect().

Secara global, dua pendekatan dimungkinkan:

1) Files.walk(Path start, )tidak memiliki maxDepthbatasan sementara

2) Files.walk(Path start, int maxDepth, FileVisitOption... options)memungkinkan untuk mengaturnya.

Tanpa menentukan batasan kedalaman apa pun, itu akan memberi:

Path directory = Paths.get("/foo/bar");

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

Dan jika karena alasan lama, Anda perlu mendapatkan Daftar FileAnda bisa menambahkan map(Path::toFile)operasi sebelum pengumpulan:

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
}
davidxxx
sumber
Ada juga Files.list(Path)yang mungkin sama dengan Files.walk(Path,1).
David L.
@David L Memang Files.list(Path)adalah alternatif yang adil jika kita tidak ingin mengulang folder secara rekursif. Untuk mengulang folder secara rekursif, walk()lebih cocok.
davidxxx
1

Solusi yang berhasil untuk saya, tidak ada di daftar jawaban. Karenanya saya memposting solusi ini di sini:

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

Disini saya telah menggunakan org.apache.commons.io.filefilter.FileFilterUtilsdari Apache commons-io-2.2.jar. Dokumentasinya tersedia di sini: https://commons.apache.org/proper/commons-io/javadocs/api-2.2/org/apache/commons/io/filefilter/FileFilterUtils.html

Abhishek Oza
sumber
0

Diberikan direktori awal sebagai String

  1. Buat metode yang menggunakan Stringjalur sebagai parameter. Dalam metode:
  2. Buat objek File baru berdasarkan direktori awal
  3. Dapatkan array file di direktori saat ini menggunakan listFilesmetode
  4. Ulangi susunan file
    1. Jika itu sebuah file, lanjutkan perulangan
    2. Jika ini adalah direktori, cetak nama dan gunakan kembali di jalur direktori baru ini
Jonathon Faust
sumber
hai, terima kasih atas balasannya. Tapi saya tidak perlu mengulang semua item dalam direktori. Saya harus mendaftar langsung subdirektori dari direktori. B'coz Saya punya banyak file dan hanya sedikit subdirektori di direktori jadi, memeriksa isDirectory () memakan waktu. tolong balas saya dengan cara lain.
Lokesh Paunikar
0

Inilah solusi untuk kode saya. Saya baru saja melakukan sedikit perubahan dari jawaban pertama . Ini akan mencantumkan semua folder hanya dalam direktori baris demi baris yang diinginkan:

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!");
        }
Tabby Auguste
sumber