2010-07-01 88 views

回答

166

您可以使用File#isDirectory()來測試給定的文件(路徑)是否是一個目錄。如果這是true,那麼您只需使用其File#listFiles()結果再次調用相同的方法。這被稱爲recursion

這是一個基本的開球示例。

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

注意,當樹比JVM的堆棧可以容納更深這是StackOverflowError敏感。您可能需要使用迭代方法或tail-recursion代替,但這是另一個主題;)

+0

非常感謝Balus,對於有多深可能是一般猜測的任何想法? – James 2010-07-01 02:56:05

+9

取決於您的JVM的內存設置。但通常有幾千像這樣的東西。如果你認爲你可能會碰到類似的目錄,那麼不要使用遞歸。 – 2010-07-01 04:06:50

+3

當文件系統在調用'isDirectory'和'listFiles'時發生'NullPointerException',就像'System.out.println'塊可能發生的情況一樣,或者你真的很不幸。檢查'listFiles'的輸出是否爲空將解決競爭條件。 – 2014-04-20 18:00:00

1

這是一棵樹,所以遞歸是你的朋友:從父目錄開始,調用方法來獲取一個子文件數組。遍歷子數組。如果當前值是一個目錄,則將其傳遞給您的方法的遞歸調用。如果不是,則適當地處理葉文件。

25

查覈在Apache的百科全書的FileUtils類 - 特別iterateFiles

允許對在給定的目錄(和可選及其子目錄)中的文件迭代。

+4

這個API是不是真正流(如果你關心的內存使用),它首先生成一個集合,只有在它返回一個迭代: 回報listFiles(目錄的FileFilter ,dirFilter).iterator(); – 2013-11-29 16:28:58

+0

Java 1.6的不錯選項。 – 2015-03-19 20:36:06

1

如上所述,這是一個遞歸問題。特別是,你可能想看看

listFiles() 

在java File API here。它返回一個目錄中所有文件的數組。與此同時使用

isDirectory() 

看看您是否需要進一步緩存是一個好的開始。

+0

鏈接斷開... !!! – 2017-04-01 11:23:18

+0

這個[link](https://docs.oracle.com/javase/8/docs/api/java/io/File.html)可能是有用的,因爲答案中的一個被破壞了。 – Donglecow 2017-06-07 09:43:05

65

如果您使用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(); 
    } 
    } 

} 
+0

有沒有一種方法可以讓流在放置新目錄時執行某個功能時放置檢查點? – 2017-12-26 15:03:40

5

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

使用虛假的,如果你不需要子目錄中的文件。

6

對於Java 7+,也有從的Javadoc採取https://docs.oracle.com/javase/7/docs/api/java/nio/file/DirectoryStream.html

例子:

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; 
} 
0

要與@msandiford答案添加,因爲大多數時候,當一個文件樹走U可以想要執行一個函數作爲一個目錄或任何特定的文件被訪問。如果你不願意使用流。覆蓋下面的方法可以實現

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