Javaでディレクトリを再帰的に削除する

Javaで再帰的にディレクトリを削除する

1. 前書き

この記事では、プレーンJavaでディレクトリを再帰的に削除する方法を説明します。 また、外部ライブラリを使用してディレクトリを削除するためのいくつかの代替方法についても見ていきます。

2. ディレクトリを再帰的に削除する

Javaには、ディレクトリを削除するオプションがあります。 ただし、これにはディレクトリが空である必要があります。 そのため、空でない特定のディレクトリを削除するには、再帰を使用する必要があります。

  1. 削除するディレクトリのすべてのコンテンツを取得します

  2. ディレクトリではないすべての子を削除します(再帰からの出口)

  3. 現在のディレクトリの各サブディレクトリについて、手順1(再帰手順)から開始します

  4. ディレクトリを削除する

この単純なアルゴリズムを実装しましょう。

boolean deleteDirectory(File directoryToBeDeleted) {
    File[] allContents = directoryToBeDeleted.listFiles();
    if (allContents != null) {
        for (File file : allContents) {
            deleteDirectory(file);
        }
    }
    return directoryToBeDeleted.delete();
}

このメソッドは、簡単なテストケースを使用してテストできます。

@Test
public void givenDirectory_whenDeletedWithRecursion_thenIsGone()
  throws IOException {

    Path pathToBeDeleted = TEMP_DIRECTORY.resolve(DIRECTORY_NAME);

    boolean result = deleteDirectory(pathToBeDeleted.toFile());

    assertTrue(result);
    assertFalse(
      "Directory still exists",
      Files.exists(pathToBeDeleted));
}

テストクラスの@Beforeメソッドは、pathToBeDeletedの場所にサブディレクトリとファイルを含むディレクトリツリーを作成し、@Afterメソッドは必要に応じてディレクトリをクリーンアップします。

次に、最も一般的に使用される2つのライブラリ(Apacheのcommons-ioとSpring Frameworkのspring-core.)を使用して削除を実行する方法を見てみましょう。これらのライブラリはどちらも、1行だけでディレクトリを削除できます。コードの。

3. commons-ioからFileUtilsを使用する

まず、commons-io依存関係をMavenプロジェクトに追加する必要があります。


    commons-io
    commons-io
    2.5

依存関係の最新バージョンはhereにあります。

これで、FileUtilsを使用して、deleteDirectory()を含む任意のファイルベースの操作を1つのステートメントで実行できます。

FileUtils.deleteDirectory(file);

4. SpringのFileSystemUtilsを使用

または、spring-core依存関係をMavenプロジェクトに追加することもできます。


    org.springframework
    spring-core
    4.3.10.RELEASE

依存関係の最新バージョンはhere.で見つけることができます

FileSystemUtilsdeleteRecursively()メソッドを使用して、削除を実行できます。

boolean result = FileSystemUtils.deleteRecursively(file);

Javaの最近のリリースでは、次のセクションで説明するようなIO操作を実行する新しい方法を提供しています。

5. Java7でのNIO2の使用

Java 7では、Filesを使用してファイル操作を実行するまったく新しい方法が導入されました。 これにより、ディレクトリツリーを走査し、実行するアクションにコールバックを使用できます。

public void whenDeletedWithNIO2WalkFileTree_thenIsGone()
  throws IOException {

    Path pathToBeDeleted = TEMP_DIRECTORY.resolve(DIRECTORY_NAME);

    Files.walkFileTree(pathToBeDeleted,
      new SimpleFileVisitor() {
        @Override
        public FileVisitResult postVisitDirectory(
          Path dir, IOException exc) throws IOException {
            Files.delete(dir);
            return FileVisitResult.CONTINUE;
        }

        @Override
        public FileVisitResult visitFile(
          Path file, BasicFileAttributes attrs)
          throws IOException {
            Files.delete(file);
            return FileVisitResult.CONTINUE;
        }
    });

    assertFalse("Directory still exists",
      Files.exists(pathToBeDeleted));
}

Files.walkFileTree()メソッドはファイルツリーをトラバースし、イベントを発行します。 これらのイベントのコールバックを指定する必要があります。 したがって、この場合、生成されたイベントに対して次のアクションを実行するようにSimpleFileVisitorを定義します。

  1. ファイルにアクセスする-削除する

  2. エントリを処理する前にディレクトリにアクセスする-何もしない

  3. エントリを処理した後にディレクトリにアクセスする-このディレクトリ内のすべてのエントリが処理される(または削除される)ため、ディレクトリを削除する

  4. ファイルにアクセスできません–失敗の原因となったIOExceptionを再スローします

ファイル操作の処理に関するNIO2APIの詳細については、Introduction to the Java NIO2 File APIを参照してください。

6. NIO2 with Java 8の使用

Java 8以降、Stream APIはディレクトリを削除するさらに優れた方法を提供します。

@Test
public void whenDeletedWithFilesWalk_thenIsGone()
  throws IOException {
    Path pathToBeDeleted = TEMP_DIRECTORY.resolve(DIRECTORY_NAME);

    Files.walk(pathToBeDeleted)
      .sorted(Comparator.reverseOrder())
      .map(Path::toFile)
      .forEach(File::delete);

    assertFalse("Directory still exists",
      Files.exists(pathToBeDeleted));
}

ここで、Files.walk()は、逆の順序でソートしたPathStreamを返します。 これにより、ディレクトリ自体の前にディレクトリの内容を示すパスが配置されます。 その後、PathFileにマップし、各File.を削除します。

7. 結論

このクイックチュートリアルでは、ディレクトリを削除するさまざまな方法を検討しました。 再帰を使用して削除する方法を見てきましたが、イベントを活用するNIO2、関数型プログラミングパラダイムを使用するJava 8パスストリームもいくつか見ました。

この記事のすべてのソースコードとテストケースは、over on Githubで入手できます。