Câu trả lời:
Bạn có thể sử dụng File#isDirectory()để kiểm tra nếu tệp đã cho (đường dẫn) là một thư mục. Nếu đây là true, sau đó bạn chỉ cần gọi lại phương thức tương tự với File#listFiles()kết quả của nó . Điều này được gọi là đệ quy .
Đây là một ví dụ khởi động cơ bản.
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());
}
}
}
Lưu ý rằng điều này nhạy cảm StackOverflowErrorkhi cây sâu hơn ngăn xếp của JVM có thể giữ. Thay vào đó, bạn có thể muốn sử dụng phương pháp lặp hoặc đệ quy đuôi , nhưng đó là một chủ đề khác;)
NullPointerExceptionkhi hệ thống tệp thay đổi giữa cuộc gọi đến isDirectoryvà listFilescó thể xảy ra nếu System.out.printlncác khối hoặc bạn thực sự không may mắn. Kiểm tra xem đầu ra listFileskhông phải là null sẽ giải quyết điều kiện cuộc đua đó.
java.nio.file.DirectoryStreamcho phép bạn lặp lại qua một thư mục và có thể được triển khai để có dấu chân bộ nhớ nhỏ nhưng cách duy nhất để biết chắc chắn sẽ là để theo dõi việc sử dụng bộ nhớ trên một nền tảng cụ thể.
Nếu bạn đang sử dụng Java 1.7, bạn có thể sử dụng java.nio.file.Files.walkFileTree(...).
Ví dụ:
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();
}
}
}
Nếu bạn đang sử dụng Java 8, bạn có thể sử dụng giao diện luồng với 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();
}
}
}
Hãy xem lớp FileUtils trong Apache Commons - cụ thể là iterateFiles :
Cho phép lặp lại các tệp trong thư mục đã cho (và tùy chọn thư mục con của nó).
Đối với Java 7+, cũng có https://docs.oracle.com/javase/7/docs/api/java/nio/file/DirectoryStream.html
Ví dụ lấy từ 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;
}
Như đã lưu ý, đây là một vấn đề đệ quy. Đặc biệt, bạn có thể muốn xem xét
listFiles()
Trong API tệp java tại đây . Nó trả về một mảng của tất cả các tệp trong một thư mục. Sử dụng cái này cùng với
isDirectory()
để xem nếu bạn cần tái diễn thêm là một khởi đầu tốt.
Để thêm bằng câu trả lời @msandiford, vì hầu hết các lần khi một cây tệp được đi, bạn có thể muốn thực thi một chức năng như một thư mục hoặc bất kỳ tệp cụ thể nào được truy cập. Nếu bạn miễn cưỡng sử dụng các luồng. Các phương pháp sau đây được ghi đè có thể được thực hiện
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;
}
});
Bạn cũng có thể sử dụng sai File.list (FilenameFilter) (và các biến thể) để truyền tải tệp. Mã ngắn và hoạt động trong các phiên bản java đầu tiên, ví dụ:
// 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;
}
});