フォルダまたはファイルのサイズを取得する


105

Javaでフォルダーまたはファイルのサイズを取得するにはどうすればよいですか?



Androidを使用している場合は、をご覧くださいStatFs。ファイルシステムの統計情報を使用し、再帰的な方法よりも約1000倍高速です。これは、私たちのニーズには使用できませんでした。私たちの実装はここにあります:stackoverflow.com/a/58418639/293280
Joshua Pinter

回答:


191
java.io.File file = new java.io.File("myfile.txt");
file.length();

これは、ファイルの長さをバイト単位で、または0ファイルが存在しない場合に返します。フォルダのサイズを取得する組み込みの方法はありません。ディレクトリを再帰的に(listFiles()ディレクトリを表すファイルオブジェクトのメソッドを使用して)ウォークし、自分でディレクトリサイズを累積する必要があります。

public static long folderSize(File directory) {
    long length = 0;
    for (File file : directory.listFiles()) {
        if (file.isFile())
            length += file.length();
        else
            length += folderSize(file);
    }
    return length;
}

警告:この方法は、実稼働で使用するには十分に堅牢ではありません。directory.listFiles()戻るnull可能性がありNullPointerExceptionます。また、シンボリックリンクを考慮せず、他の失敗モードを持っている可能性があります。この方法を使用ます。


11
これをWindowsマシンのC:ルートディレクトリで実行する場合は注意してください。(java.io.Fileによると)ファイルでもディレクトリでもないシステムファイルがあります。else-clauseを変更して、ファイルが実際にディレクトリであることを確認することができます。
Paul Clapham、2010年

2
パラメータをチェックしてメソッドの最初のディレクトリではないかどうかを確認し、長さを返す単純な変更。再帰はより簡単です。同じメソッドでselfへの呼び出しを追加するだけで、代わりにファイル参照を渡すことができます。ディレクトリも同様です。
Kevin Brock

3
Java 7以降を使用している場合は、stackoverflow.com / a / 19877372/40064の回答を使用してください。
Wim Deblauwe

1
これはシンボリックリンクによって混乱します。また、NullPointerExceptionディレクトリが同時に変更された場合にもスローされることがあります。
Aleksandr Dubinsky

43

java-7 nio apiを使用すると、フォルダーサイズの計算を大幅に高速化できます。

堅牢で例外をスローしない、すぐに実行できる例を次に示します。入力できないディレクトリ、またはトラバースに問題があったディレクトリをログに記録します。シンボリックリンクは無視され、ディレクトリを同時に変更しても、必要以上に問題が発生することはありません。

/**
 * Attempts to calculate the size of a file or directory.
 * 
 * <p>
 * Since the operation is non-atomic, the returned value may be inaccurate.
 * However, this method is quick and does its best.
 */
public static long size(Path path) {

    final AtomicLong size = new AtomicLong(0);

    try {
        Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {

                size.addAndGet(attrs.size());
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult visitFileFailed(Path file, IOException exc) {

                System.out.println("skipped: " + file + " (" + exc + ")");
                // Skip folders that can't be traversed
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult postVisitDirectory(Path dir, IOException exc) {

                if (exc != null)
                    System.out.println("had trouble traversing: " + dir + " (" + exc + ")");
                // Ignore errors traversing a folder
                return FileVisitResult.CONTINUE;
            }
        });
    } catch (IOException e) {
        throw new AssertionError("walkFileTree will not throw IOException if the FileVisitor does not");
    }

    return size.get();
}

Android開発でこれに相当するものはありますか?
Android開発者

AtomicLong代わりに使用する理由はありlongますか?
Lukas Schmelzeisen 2014

変数は、匿名クラスからアクセスされた場合はfinalでなければなりません
Aksel Willgert '28 / 12/28

1
私はJMHを使用してベンチマークを実行しました。このNIO apiメソッドは、commons-ioコード(合計180229ファイルの多くのサブフォルダーを持つフォルダーでテスト済み)に比べて約4〜5倍高速です。Commons IOは15秒かかり、NIOは5秒かかりました。
Wim Deblauwe

3
このアプローチが最も堅牢です。シンボリックリンク、同時変更、セキュリティ例外を扱い、ファイルとディレクトリの両方で動作します。残念Filesながら、直接サポートしていません。
Aleksandr Dubinsky、2015年

38

commons-ioFileUtils#sizeOfDirectory(File)から必要です。

非ディレクトリが渡された場合にメソッドが例外をスローするため、ファイルがディレクトリであるかどうかを手動で確認する必要があることに注意してください。

警告:このメソッド(commons-io 2.4以降)にはバグがありIllegalArgumentException、ディレクトリが同時に変更されるとスローされる場合があります。


では、ファイルがディレクトリでない場合はどうなりますか?それが存在しないとき?等-どのようにひどいドキュメント
Mr_and_Mrs_D

@Mr_and_Mrs_D- checkDirectory(directory);チェック後の行をコピーして貼り付けます。File.listFiles子供がいることを確認してください。参照: FileUtils.sizeOfDirectory()File.listFiles()
Mr. Polywhirl

3
バグIO-449を参照してください。このメソッドIllegalArgumentExceptionは、反復中にディレクトリが変更された場合にスローします。
Aleksandr Dubinsky、2015年

痛い!!! それはうんざりです...ええ、それはファイルを一覧表示し、コードの実行中にファイルが削除されるとスローします。
ディーン・ヒラー

19

Java 8の場合:

long size = Files.walk(path).mapToLong( p -> p.toFile().length() ).sum();

それを使用する方がいいでしょう Files::sizeマップステップでした方、チェック例外がスローされます。

更新:
一部のファイル/フォルダーにアクセスできない場合、これが例外をスローする可能性があることにも注意してください。この質問Guavaを使用した別のソリューションをご覧ください。


1
私は同様のことを調べていて、問題のコードであるstackoverflow.com/questions/22867286/…で終わっていました。
Aksel Willgert 14

@AkselWillgertおかげで、これは残念なことであり、私は答えを更新しました。現在グアバに切り替えていますstackoverflow.com/a/24757556/1180621
Andrejs

10
public static long getFolderSize(File dir) {
    long size = 0;
    for (File file : dir.listFiles()) {
        if (file.isFile()) {
            System.out.println(file.getName() + " " + file.length());
            size += file.length();
        }
        else
            size += getFolderSize(file);
    }
    return size;
}

1
@Vishalコードには簡単な修正が必要です。再帰呼び出しでは、サイズを既存のサイズに追加するだけでなく、追加する必要があります。 size += getFolderSize(file);
Teja Kantamneni 2010年

@Teja:指摘いただきありがとうございますが、ifステートメントにも変更が加えられます
Vishal

時々、増大するフォルダー(別のスレッドがファイルとフォルダーをダウンロードし、同時に進行中にフォルダーサイズを出力しています)で、「for(File file:dir.listFiles()){」の行にnullpointerexceptionが表示されます。一部のファイルは、生きているフォルダに表示され、すぐに消えます。そのため、forループの前にdir.listFiles()の戻り値のnullチェックを追加しました。
csonuryilmaz

File.listFiles()javadocから:「ディレクトリが空の場合、配列は空になります。この抽象パス名がディレクトリを示していない場合、またはI / Oエラーが発生した場合は、nullを返します。」したがって、上記のコメントは、動的に変化するフォルダーのフォルダーサイズを取得するときに役立ちます。
csonuryilmaz

7

以下のためのJava 8、これはそれを行うには1つの正しい方法です。

Files.walk(new File("D:/temp").toPath())
                .map(f -> f.toFile())
                .filter(f -> f.isFile())
                .mapToLong(f -> f.length()).sum()

すべてのディレクトリを除外することが重要です。これはディレクトリのlengthメソッドが0であることが保証されていないためです。

少なくともこのコードは、Windowsエクスプローラ自体と同じサイズの情報を提供します。


4

一般的なファイルのサイズを取得する最良の方法は次のとおりです(ディレクトリと非ディレクトリで機能します)。

public static long getSize(File file) {
    long size;
    if (file.isDirectory()) {
        size = 0;
        for (File child : file.listFiles()) {
            size += getSize(child);
        }
    } else {
        size = file.length();
    }
    return size;
}

編集:これはおそらく時間がかかる操作になることに注意してください。UIスレッドでは実行しないでください。

また、ここ(https://stackoverflow.com/a/5599842/1696171から取得)は、返されたlongからユーザーが読み取り可能な文字列を取得するための優れた方法です。

public static String getReadableSize(long size) {
    if(size <= 0) return "0";
    final String[] units = new String[] { "B", "KB", "MB", "GB", "TB" };
    int digitGroups = (int) (Math.log10(size)/Math.log10(1024));
    return new DecimalFormat("#,##0.#").format(size/Math.pow(1024, digitGroups))
            + " " + units[digitGroups];
}

4

Java 8 NIO API を使用する場合、次のプログラムは、それが配置されているディレクトリのサイズをバイト単位で出力します。

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class PathSize {

    public static void main(String[] args) {
        Path path = Paths.get(".");
        long size = calculateSize(path);
        System.out.println(size);
    }

    /**
     * Returns the size, in bytes, of the specified <tt>path</tt>. If the given
     * path is a regular file, trivially its size is returned. Else the path is
     * a directory and its contents are recursively explored, returning the
     * total sum of all files within the directory.
     * <p>
     * If an I/O exception occurs, it is suppressed within this method and
     * <tt>0</tt> is returned as the size of the specified <tt>path</tt>.
     * 
     * @param path path whose size is to be returned
     * @return size of the specified path
     */
    public static long calculateSize(Path path) {
        try {
            if (Files.isRegularFile(path)) {
                return Files.size(path);
            }

            return Files.list(path).mapToLong(PathSize::calculateSize).sum();
        } catch (IOException e) {
            return 0L;
        }
    }

}

このcalculateSizeメソッドはPathオブジェクトに対して普遍的であるため、ファイルに対しても機能します。 ファイルまたはディレクトリにアクセスできない場合、この場合に返されるというサイズパスオブジェクトのがになります0


3

File.length()Javadoc)。

これはディレクトリでは機能しないか、機能することが保証されていないことに注意してください。

ディレクトリの場合、何が必要ですか?それがその下にあるすべてのファイルの合計サイズである場合、を使用File.list()して子供たちを再帰的に歩きFile.isDirectory()、そのサイズを合計できます。


3

Fileオブジェクトが持つlengthメソッドを:

f = new File("your/file/name");
f.length();

3
  • 以下のための作品のAndroid Javaの
  • フォルダとファイルの両方で機能します
  • 必要な場所すべてでnullポインターをチェックします
  • シンボリックリンクを無視しますつまりショートカットを
  • 生産準備完了!

ソースコード:

   public long fileSize(File root) {
        if(root == null){
            return 0;
        }
        if(root.isFile()){
            return root.length();
        }
        try {
            if(isSymlink(root)){
                return 0;
            }
        } catch (IOException e) {
            e.printStackTrace();
            return 0;
        }

        long length = 0;
        File[] files = root.listFiles();
        if(files == null){
            return 0;
        }
        for (File file : files) {
            length += fileSize(file);
        }

        return length;
    }

    private static boolean isSymlink(File file) throws IOException {
        File canon;
        if (file.getParent() == null) {
            canon = file;
        } else {
            File canonDir = file.getParentFile().getCanonicalFile();
            canon = new File(canonDir, file.getName());
        }
        return !canon.getCanonicalFile().equals(canon.getAbsoluteFile());
    }

1

Windowsの場合、java.ioを使用すると、この再帰関数が役立ちます。

    public static long folderSize(File directory) {
    long length = 0;

    if (directory.isFile())
         length += directory.length();
    else{
        for (File file : directory.listFiles()) {
             if (file.isFile())
                 length += file.length();
             else
                 length += folderSize(file);
        }
    }

    return length;
}

これはテストされ、私の側で適切に動作しています。


1

私はテストdu -c <folderpath>しましたが、nioよりも2倍高速です。ファイルまたは再帰

private static long getFolderSize(File folder){
  if (folder != null && folder.exists() && folder.canRead()){
    try {
      Process p = new ProcessBuilder("du","-c",folder.getAbsolutePath()).start();
      BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
      String total = "";
      for (String line; null != (line = r.readLine());)
        total = line;
      r.close();
      p.waitFor();
      if (total.length() > 0 && total.endsWith("total"))
        return Long.parseLong(total.split("\\s+")[0]) * 1024;
    } catch (Exception ex) {
      ex.printStackTrace();
    }
  }
  return -1;
}

0
public long folderSize (String directory)
    {
        File curDir = new File(directory);
        long length = 0;
        for(File f : curDir.listFiles())
        {
            if(f.isDirectory())
            {               
                 for ( File child : f.listFiles()) 
                 {
                     length = length + child.length();
                 }

                System.out.println("Directory: " + f.getName() + " " + length + "kb");
            }
            else
            {
                length = f.length();
                System.out.println("File: " + f.getName() + " " + length + "kb");
            }
            length = 0;
        }
        return length;
    }

0

ここでStackOverflowで提案されたさまざまなソリューションについて多くの調査と調査を行った後。ようやく自分のソリューションを書くことにしました。APIがフォルダーサイズを取得できない場合にクラッシュしたくないので、私の目的は、スローしないメカニズムを持つことです。この方法は、マルチスレッドシナリオには適していません。

まず、ファイルシステムツリーをたどって、有効なディレクトリを確認します。

private static boolean isValidDir(File dir){
    if (dir != null && dir.exists() && dir.isDirectory()){
        return true;
    }else{
        return false;
    }
}

第二に、再帰呼び出しをシンボリックリンク(ソフトリンク)に入れて、全体のサイズを含めたくありません。

public static boolean isSymlink(File file) throws IOException {
    File canon;
    if (file.getParent() == null) {
        canon = file;
    } else {
        canon = new File(file.getParentFile().getCanonicalFile(),
                file.getName());
    }
    return !canon.getCanonicalFile().equals(canon.getAbsoluteFile());
}

最後に、指定したディレクトリのサイズを取得するための再帰ベースの実装です。dir.listFiles()のnullチェックに注意してください。javadocによると、このメソッドがnullを返す可能性があります。

public static long getDirSize(File dir){
    if (!isValidDir(dir))
        return 0L;
    File[] files = dir.listFiles();
    //Guard for null pointer exception on files
    if (files == null){
        return 0L;
    }else{
        long size = 0L;
        for(File file : files){
            if (file.isFile()){
                size += file.length();
            }else{
                try{
                    if (!isSymlink(file)) size += getDirSize(file);
                }catch (IOException ioe){
                    //digest exception
                }
            }
        }
        return size;
    }
}

ケーキのクリーム、リストファイルのサイズを取得するAPI(ルートの下のすべてのファイルとフォルダーである可能性があります)。

public static long getDirSize(List<File> files){
    long size = 0L;
    for(File file : files){
        if (file.isDirectory()){
            size += getDirSize(file);
        } else {
            size += file.length();
        }
    }
    return size;
}

0

Linuxでディレクトリを並べ替える場合は、du -hs * | ソート-h


0

を使用Apache Commons IOして、フォルダのサイズを簡単に見つけることができます。

mavenを使用している場合は、次の依存関係をpom.xmlファイルに追加してください。

<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.6</version>
</dependency>

Mavenのファンでない場合は、次のjarをダウンロードしてクラスパスに追加します。

https://repo1.maven.org/maven2/commons-io/commons-io/2.6/commons-io-2.6.jar

public long getFolderSize() {

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

    return size; // in bytes
}

Commons IOを介してファイルサイズを取得するには、

File file = new File("ADD YOUR PATH TO FILE");

long fileSize = FileUtils.sizeOf(file);

System.out.println(fileSize); // bytes

それはまた達成することができます Google Guava

Mavenの場合、以下を追加します。

<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>28.1-jre</version>
</dependency>

Mavenを使用しない場合は、以下をクラスパスに追加します

https://repo1.maven.org/maven2/com/google/guava/guava/28.1-jre/guava-28.1-jre.jar

public long getFolderSizeViaGuava() {
        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();

        return  size;
    }

ファイルサイズを取得するには、

 File file = new File("PATH TO YOUR FILE");
 long s  = file.length();
 System.out.println(s);

0
private static long getFolderSize(Path folder) {
        try {
            return Files.walk(folder)
                      .filter(p -> p.toFile().isFile())
                      .mapToLong(p -> p.toFile().length())
                      .sum();
        } catch (IOException e) {
            e.printStackTrace();
            return 0L;
        }

あなたのコードは良く見えますが、それが他の答えに何かを追加するかどうかはわかりません。含まれている場合は、回答を編集して説明してください。
Dragonthoughts、

これは、同じ行を少ないコード行で実行する更新バージョンにすぎません。
Jaskaran Singh
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.