Javaのディレクトリ内のファイルを反復処理するにはどうすればよいですか?


175

すべてのサブディレクトリ内のファイルを含む、ディレクトリ内のすべてのファイルのリストを取得する必要があります。Javaでディレクトリの反復を実現する標準的な方法は何ですか?

回答:


207

を使用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のスタックが保持できるよりも深い場合に影響を受けやすいことに注意してください。代わりに、反復アプローチまたは末尾再帰を使用することもできますが、それは別のテーマです;)


Balusに感謝します。一般的な推測として、それがどれほど深いかについての考えはありますか?
Jamesが

10
JVMのメモリ設定によって異なります。しかし、一般的には数千のようなものです。そのようなディレクトリに出くわす可能性があると思われる場合は、再帰を使用しないでください。
Mike Baranczak 2010

4
これは、影響を受けやすいNullPointerExceptionファイルシステムがへの呼び出しの間で変化したときisDirectorylistFiles場合に発生する可能性があるとして、System.out.printlnブロックまたはあなたが本当に不運得ます。の出力がlistFilesnullでないことを確認すると、その競合状態が解決されます。
マイクサミュエル

1
@BoratSagdiyev、古いJavaファイルAPIを使用していませんが、最新のJVMをjava.nio.file.DirectoryStream使用している場合は、ディレクトリを反復処理でき、メモリフットプリントが小さいように実装できますが、確実に伝える唯一の方法は特定のプラットフォームでのメモリ使用量を監視します。
マイクサミュエル

1
「C:\\」フォルダは、例として最良の選択ではありません)
Vyacheslav

86

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

}

1
新しいディレクトリがウォークされたときにチェックポイントを配置して関数を実行する方法はありますか?
Raghu DV

28

Apache CommonsのFileUtilsクラス、特にiterateFilesを確認してください。

指定されたディレクトリ(およびオプションでそのサブディレクトリ)内のファイルの反復を許可します。


5
このAPIは本当にストリーミングしていません(memの使用法に関心がある場合)。最初にコレクションを生成し、次にそれに対するイテレータを返します。return listFiles(directory、fileFilter、dirFilter).iterator();
Gili Nachum 2013年

Java 1.6に適したオプションです。
デビッドI.

@GiliNachumに同意します。ApacheのFileUtilsは最初にすべてのファイルを収集し、それらにイテレータを提供します。ファイルが大量にある場合、リソースにとって有害で​​す。
ボグダンサモンドロス

8

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

8

使用する 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を使用します。


3

それはツリーなので、再帰はあなたの友人です:親ディレクトリから始めて、メソッドを呼び出して子ファイルの配列を取得します。子配列を反復処理します。現在の値がディレクトリの場合、それをメソッドの再帰呼び出しに渡します。そうでない場合は、リーフファイルを適切に処理します。


2

前述のように、これは再帰の問題です。特に、あなたは見てみたいかもしれません

listFiles() 

ここのJavaファイルAPI 。ディレクトリ内のすべてのファイルの配列を返します。これを一緒に使う

isDirectory()

さらに再帰する必要があるかどうかを確認することは、良いスタートです。


回答のリンクが壊れているので、このリンク役に立つかもしれません。
Donglecow 2017年

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

0

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;
    }
});
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.