回答:
を使用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
nullでないことを確認すると、その競合状態が解決されます。
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();
}
}
}
Apache CommonsのFileUtilsクラス、特に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;
}
@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;
}
});
File.list(FilenameFilter)(およびバリアント)をファイルトラバーサルに誤用することもできます。短いコードで、初期のJavaバージョンで動作します。例:
// 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;
}
});