ฉันต้องการรายชื่อของไฟล์ทั้งหมดในไดเรกทอรีรวมถึงไฟล์ในทุกไดเรกทอรีย่อย วิธีมาตรฐานในการทำซ้ำไดเรกทอรีด้วย Java คืออะไร?
ฉันต้องการรายชื่อของไฟล์ทั้งหมดในไดเรกทอรีรวมถึงไฟล์ในทุกไดเรกทอรีย่อย วิธีมาตรฐานในการทำซ้ำไดเรกทอรีด้วย Java คืออะไร?
คำตอบ:
คุณสามารถใช้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());
}
}
}
โปรดทราบว่านี่เป็นเรื่องละเอียดอ่อนStackOverflowErrorเมื่อต้นไม้ลึกกว่าสแต็กของ JVM ที่สามารถเก็บไว้ได้ คุณอาจต้องการใช้วิธีการวนซ้ำหรือเรียกซ้ำแบบหางปลาไหลแทน แต่นั่นเป็นอีกเรื่องหนึ่ง;)
NullPointerExceptionเมื่อระบบไฟล์เปลี่ยนไประหว่างการเรียกisDirectoryและlistFilesอาจเกิดขึ้นถ้าSystem.out.printlnบล็อกหรือคุณเพิ่งได้รับโชคร้ายจริงๆ การตรวจสอบว่าผลลัพธ์ของlistFilesไม่เป็นโมฆะจะแก้ไขเงื่อนไขการแข่งขันนั้น
java.nio.file.DirectoryStreamจะอนุญาตให้คุณทำซ้ำในไดเรกทอรีและสามารถนำไปใช้กับหน่วยความจำขนาดเล็ก แต่วิธีเดียวที่จะบอกได้อย่างแน่นอน เพื่อตรวจสอบการใช้งานหน่วยความจำบนแพลตฟอร์มเฉพาะ
หากคุณกำลังใช้ 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 คอมมอนส์ - เฉพาะiterateFiles :
อนุญาตให้วนซ้ำไฟล์ในไดเรกทอรีที่กำหนด (และอาจเป็นไดเรกทอรีย่อย)
สำหรับ 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;
}
การใช้ 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 ถ้าคุณไม่ต้องการไฟล์จากไดเรกทอรีย่อย
มันเป็นต้นไม้ดังนั้นการเรียกซ้ำเป็นเพื่อนของคุณ: เริ่มต้นด้วยไดเรกทอรีหลักและเรียกวิธีการรับอาร์เรย์ของไฟล์ย่อย วนซ้ำผ่านอาร์เรย์เด็ก หากค่าปัจจุบันเป็นไดเรกทอรีให้ส่งผ่านไปยังการเรียกซ้ำของวิธีการของคุณ หากไม่มีให้ประมวลผลไฟล์ leaf อย่างเหมาะสม
หากต้องการเพิ่มด้วยคำตอบ @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;
}
});
คุณยังสามารถใช้ File.list (FilenameFilter) ในทางที่ผิด (และตัวแปร) สำหรับการแวะผ่านไฟล์ โค้ดย่อและใช้งานได้ในเวอร์ชันจาวารุ่นแรกเช่น:
// 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;
}
});