Java - ディレクトリサイズ

1概要

このチュートリアルでは、Java 6、7と新しいJava 8、さらにGuavaとApache Common IOを使用して、Javaでフォルダのサイズを取得する方法を学習します。

2 Java を使う

フォルダのサイズを計算する簡単な例から始めましょう - その内容の合計を使って :

private long getFolderSize(File folder) {
    long length = 0;
    File[]files = folder.listFiles();

    int count = files.length;

    for (int i = 0; i < count; i++) {
        if (files[i].isFile()) {
            length += files[i].length();
        }
        else {
            length += getFolderSize(files[i]);
        }
    }
    return length;
}

次の例のように、メソッド getFolderSize() をテストできます。

@Test
public void whenGetFolderSizeRecursive__thenCorrect() {
    long expectedSize = 12607;

    File folder = new File("src/test/resources");
    long size = getFolderSize(folder);

    assertEquals(expectedSize, size);
}

注: listFiles() は、指定されたフォルダの内容を一覧表示するために使用されます。

3 Java 7 の場合

次に、フォルダサイズを取得するためのJava 7の使い方を見てみましょう。次の例では、 Files.walkFileTree() を使用して、フォルダ内のすべてのファイルをトラバースしてサイズを合計します。

@Test
public void whenGetFolderSizeUsingJava7__thenCorrect() throws IOException {
    long expectedSize = 12607;

    AtomicLong size = new AtomicLong(0);
    Path folder = Paths.get("src/test/resources");

    Files.walkFileTree(folder, new SimpleFileVisitor<Path>() {
        @Override
        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
          throws IOException {
            size.addAndGet(attrs.size());
            return FileVisitResult.CONTINUE;
        }
    });

    assertEquals(expectedSize, size.longValue());
}

ここでは、ファイルシステムツリーの走査機能をどのように利用し、各ファイルとサブフォルダーのサイズを計算して計算するのに役立つ訪問者パターンを利用しているかに注目してください。

4 Java 8 の場合

それでは、 Java 8、ストリーム操作、およびラムダ を使用してフォルダーサイズを取得する方法を見てみましょう。次の例では、 Files.walk() を使用してフォルダ内のすべてのファイルを走査してサイズを合計します。

@Test
public void whenGetFolderSizeUsingJava8__thenCorrect() throws IOException {
    long expectedSize = 12607;

    Path folder = Paths.get("src/test/resources");
    long size = Files.walk(folder)
      .filter(p -> p.toFile().isFile())
      .mapToLong(p -> p.toFile().length())
      .sum();

    assertEquals(expectedSize, size);
}

注: mapToLong() は、各要素に length 関数を適用して LongStream を生成するために使用されます。その後、 sum を実行して最終結果を取得できます。

5 Apache Commons IO を使う

次に、Apache Commons IOを使ってフォルダサイズを取得する方法を見てみましょう。

次の例では、フォルダサイズを取得するために FileUtils.sizeOfDirectory() を使用しています。

@Test
public void whenGetFolderSizeUsingApacheCommonsIO__thenCorrect() {
    long expectedSize = 12607;

    File folder = new File("src/test/resources");
    long size = FileUtils.sizeOfDirectory(folder);

    assertEquals(expectedSize, size);
}

これはポイントユーティリティメソッドに対して、内部では単純なJava 6ソリューションを実装していることに注意してください。

また、このライブラリでは、セキュリティが制限されたディレクトリをより適切に処理するための FileUtils.sizeOfDirectoryAsBigInteger() メソッドも提供されています。

6. グアバ とは

それでは、 Guava を使用してフォルダのサイズを計算する方法を見てみましょう。次の例では、 Files.fileTreeTraverser() を使用して、フォルダ内のすべてのファイルのサイズを合計します。

@Test
public void whenGetFolderSizeUsingGuava__thenCorrect() {
    long expectedSize = 12607;

    File folder = new File("src/test/resources");

    Iterable<File> files = Files.fileTreeTraverser()
          .breadthFirstTraversal(folder);
    long size = StreamSupport.stream(files.spliterator(), false)
      .filter(f -> f.isFile())
      .mapToLong(File::length).sum();

    assertEquals(expectedSize, size);
}

7. 人間が読めるサイズ

最後に、バイト単位のサイズではなく、より読みやすいフォルダサイズの表現を取得する方法を見てみましょう。

@Test
public void whenGetReadableSize__thenCorrect() {
    File folder = new File("src/test/resources");
    long size = getFolderSize(folder);

    String[]units = new String[]{ "B", "KB", "MB", "GB", "TB" };
    int unitIndex = (int) (Math.log10(size)/3);
    double unitValue = 1 << (unitIndex **  10);

    String readableSize = new DecimalFormat("#,##0.#")
                                .format(size/unitValue) + " "
                                + units[unitIndex];
    assertEquals("12.3 KB", readableSize);
}

注:結果を小数点以下第1位に丸めるために DecimalFormat(“#、## 0、#”) を使用しました。

8ノート

フォルダサイズの計算に関する注意事項は次のとおりです。

  • Files.walk() Files.walkFileTree() の両方が、

セキュリティーマネージャーが開始ファイルへのアクセスを拒否した場合はSecurityException。

  • フォルダにシンボリックリンクが含まれていると、無限ループが発生する可能性があります。

9結論

このクイックチュートリアルでは、ファイルシステム内のディレクトリのサイズを計算するために、異なる Java バージョン、 Apache Commons IO 、および Guava を使用する例を示しました。

これらの例の実装はhttps://github.com/eugenp/tutorials/tree/master/core-java-io[GitHubプロジェクト]にあります - これはMavenベースのプロジェクトなので、簡単に実行できます。そのままインポートして実行します。