Größe des Ordners oder der Datei abrufen

105

Wie kann ich die Größe eines Ordners oder einer Datei in Java abrufen?

oneat
quelle
Gleich, aber mit Fokus auf Effizienz: stackoverflow.com/questions/116574/…
Ciro Santilli 法轮功 冠状 病 六四 事件 2
Wenn Sie zufällig auf Android sind , schauen Sie sich das an StatFs. Es verwendet Dateisystemstatistiken und ist fast 1000-mal schneller als rekursive Methoden, die für unsere Anforderungen unbrauchbar waren. Unsere Implementierung finden Sie hier: stackoverflow.com/a/58418639/293280
Joshua Pinter

Antworten:

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

Dies gibt die Länge der Datei in Bytes zurück oder 0wenn die Datei nicht existiert. Es gibt keine integrierte Methode, um die Größe eines Ordners zu ermitteln. Sie müssen den Verzeichnisbaum rekursiv durchsuchen (mithilfe der listFiles()Methode eines Dateiobjekts, das ein Verzeichnis darstellt) und die Verzeichnisgröße selbst akkumulieren:

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

WARNUNG : Diese Methode ist für den Einsatz in der Produktion nicht robust genug. directory.listFiles()kann zurückkehren nullund a verursachen NullPointerException. Außerdem werden Symlinks nicht berücksichtigt und es gibt möglicherweise andere Fehlermodi. Verwenden Sie diese Methode .

Tendayi Mawushe
quelle
11
Seien Sie vorsichtig, wenn Sie dies im Stammverzeichnis C: auf einem Windows-Computer ausführen. Dort gibt es eine Systemdatei, die (laut java.io.File) weder eine Datei noch ein Verzeichnis ist. Möglicherweise möchten Sie die else-Klausel ändern, um zu überprüfen, ob die Datei tatsächlich ein Verzeichnis ist.
Paul Clapham
2
Einfache Änderung, um den Parameter zu überprüfen, um festzustellen, ob es sich am Anfang der Methode nicht um ein Verzeichnis handelt, und um die Länge zurückzugeben. Dann ist die Rekursion einfacher. Fügen Sie einfach den Aufruf von self in derselben Methode hinzu, und dies unterstützt stattdessen die Übergabe einer Dateireferenz eines Verzeichnisses auch.
Kevin Brock
3
Wenn Sie Java 7 oder höher verwenden, verwenden Sie die Antwort stackoverflow.com/a/19877372/40064, es ist viel schneller.
Wim Deblauwe
1
Dies wird durch Symlinks verwirrt. Es kann auch ein auslösen, NullPointerExceptionwenn das Verzeichnis gleichzeitig geändert wird.
Aleksandr Dubinsky
43

Mit Java-7 nio api kann die Ordnergröße viel schneller berechnet werden.

Hier ist ein sofort einsatzbereites Beispiel, das robust ist und keine Ausnahme auslöst. Es werden Verzeichnisse protokolliert, in die es nicht eintreten kann oder die Probleme beim Durchlaufen hatten. Symlinks werden ignoriert und die gleichzeitige Änderung des Verzeichnisses verursacht nicht mehr Probleme als nötig.

/**
 * 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();
}
Aksel Willgert
quelle
Gibt es dafür ein Äquivalent zur Android-Entwicklung?
Android-Entwickler
Gibt es einen Grund für die Verwendung AtomicLongstatt nur long?
Lukas Schmelzeisen
Die Variable muss endgültig sein, wenn von einer anonymen Klasse zugegriffen wird
Aksel Willgert
1
Ich habe einen Benchmark mit JMH durchgeführt und diese NIO-API-Methode ist etwa vier- bis fünfmal schneller als der Commons-Io-Code (getestet in einem Ordner mit vielen Unterordnern für insgesamt 180229 Dateien). Commons IO dauerte 15 Sekunden, NIO 5 Sekunden.
Wim Deblauwe
3
Dieser Ansatz ist der robusteste. Es befasst sich mit Symlinks, gleichzeitigen Änderungen, Sicherheitsausnahmen, funktioniert sowohl mit Dateien als auch mit Verzeichnissen usw. Es ist schade, dass Fileses nicht direkt unterstützt wird!
Aleksandr Dubinsky
38

Sie benötigen FileUtils#sizeOfDirectory(File)von Commons-Io .

Beachten Sie, dass Sie manuell überprüfen müssen, ob die Datei ein Verzeichnis ist, da die Methode eine Ausnahme auslöst, wenn ein Nichtverzeichnis an sie übergeben wird.

WARNUNG : Diese Methode (ab Commons-Io 2.4) hat einen Fehler und kann ausgelöst werden, IllegalArgumentExceptionwenn das Verzeichnis gleichzeitig geändert wird.

yegor256
quelle
Was passiert also, wenn die Datei kein Verzeichnis ist? wenn es nicht existiert? etc - wie schrecklich docs
Mr_and_Mrs_D
@Mr_and_Mrs_D - Kopieren Sie einfach die Zeilen und fügen Sie sie nach der checkDirectory(directory);Prüfung ein. Stellen Sie einfach sicher, dass File.listFilesKinder haben. Refs: FileUtils.sizeOfDirectory () , File.listFiles ()
Mr. Polywhirl
3
Siehe Fehler IO-449 . Diese Methode löst ein aus, IllegalArgumentExceptionwenn das Verzeichnis während der Iteration geändert wird.
Aleksandr Dubinsky
Autsch!!! Das ist scheiße ... ja, es listet Dateien auf und wenn dann eine gelöscht wird, während der Code ausgeführt wird, wirft es.
Dean Hiller
19

In Java 8:

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

Es wäre schöner, Files::sizeim Kartenschritt zu verwenden, aber es wird eine aktivierte Ausnahme ausgelöst.

UPDATE:
Sie sollten sich auch bewusst sein, dass dies eine Ausnahme auslösen kann, wenn auf einige der Dateien / Ordner nicht zugegriffen werden kann. Siehe diese Frage und eine andere Lösung mit Guava .

Andrejs
quelle
1
Ich habe mich mit etwas Ähnlichem befasst und am Ende den fraglichen Code gefunden: stackoverflow.com/questions/22867286/… , wie Sie sehen, gibt es einen weiteren Aspekt der Fehlerbehandlung, der ebenfalls Probleme verursacht.
Aksel Willgert
@ AkselWillgert Danke, das ist bedauerlich und ich habe die Antwort aktualisiert. Wechseln Sie jetzt zu Guava 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;
}
Vishal
quelle
1
@Vishal Ihr Code muss eine einfache Korrektur haben. Beim rekursiven Aufruf sollten Sie die Größe zur vorhandenen Größe hinzufügen und nicht nur zuweisen. size += getFolderSize(file);
Teja Kantamneni
@ Teja: Danke für den Hinweis, aber die Änderungen werden auch in der if-Anweisung sein
Vishal
Manchmal gibt es in einem wachsenden Ordner (ein anderer Thread lädt Dateien und Ordner herunter und gleichzeitig drucke ich die Ordnergröße im Verlauf) nullpointerexception in Zeile "for (File file: dir.listFiles ()) {". Einige Dateien werden in einem lebenden Ordner schnell angezeigt und ausgeblendet. Also habe ich eine Nullprüfung für den Rückgabewert dir.listFiles () vor der for-Schleife hinzugefügt .
Csonuryilmaz
Aus File.listFiles () javadoc: "Das Array ist leer, wenn das Verzeichnis leer ist. Gibt null zurück, wenn dieser abstrakte Pfadname kein Verzeichnis bezeichnet oder wenn ein E / A-Fehler auftritt." Der obige Kommentar ist daher nützlich, wenn Sie die Ordnergröße für sich dynamisch ändernde Ordner ermitteln möchten.
Csonuryilmaz
7

Für Java 8 ist dies ein richtiger Weg:

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

Es ist wichtig, alle Verzeichnisse herauszufiltern , da die Längenmethode für Verzeichnisse nicht garantiert 0 ist.

Zumindest liefert dieser Code die gleichen Größeninformationen wie der Windows Explorer.

wumpz
quelle
4

Hier ist der beste Weg, um die Größe einer allgemeinen Datei zu ermitteln (funktioniert für Verzeichnisse und Nichtverzeichnisse):

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

Bearbeiten: Beachten Sie, dass dies wahrscheinlich ein zeitaufwändiger Vorgang sein wird. Führen Sie es nicht im UI-Thread aus.

Auch hier (entnommen aus https://stackoverflow.com/a/5599842/1696171 ) ist eine gute Möglichkeit, einen benutzerlesbaren String aus dem lange zurückgegebenen zu erhalten:

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];
}
Eric Cochran
quelle
4

Wenn Sie die Java 8 NIO- API verwenden möchten, druckt das folgende Programm die Größe des Verzeichnisses in Byte, in dem es sich befindet.

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

}

Die calculateSizeMethode ist universell für PathObjekte und funktioniert daher auch für Dateien. Beachten Sie, dass in diesem Fall die zurückgegebene Größe des Pfadobjekts lautet, wenn auf eine Datei oder ein Verzeichnis nicht zugegriffen werden kann 0.

dinomario10
quelle
3

File.length()( Javadoc ).

Beachten Sie, dass dies für Verzeichnisse nicht funktioniert oder nicht garantiert funktioniert.

Was möchten Sie für ein Verzeichnis? Wenn es sich um die Gesamtgröße aller darunter liegenden Dateien handelt, können Sie Kinder mit File.list()und rekursiv spazieren gehen File.isDirectory()und ihre Größe summieren.

danben
quelle
3

Das FileObjekt hat eine lengthMethode:

f = new File("your/file/name");
f.length();
JesperE
quelle
3
  • Funktioniert für Android und Java
  • Funktioniert sowohl für Ordner als auch für Dateien
  • Überprüft überall, wo dies erforderlich ist, auf Nullzeiger
  • Ignoriert symbolische Verknüpfungen oder Verknüpfungen
  • Produktionsbereit!

Quellcode:

   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());
    }
Ilya Gazman
quelle
1

Für Windows ist diese rekursive Funktion mit java.io nützlich.

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

Dies ist getestet und funktioniert an meinem Ende richtig.

Es ist PD
quelle
1

Ich habe getestet du -c <folderpath>und ist 2x schneller als nio.Files oder Rekursion

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;
}
G Dias
quelle
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;
    }
Nikolaus
quelle
0

Nach vielen Recherchen und Untersuchungen zu verschiedenen Lösungen, die hier bei StackOverflow vorgeschlagen wurden. Ich beschloss schließlich, meine eigene Lösung zu schreiben. Mein Zweck ist ein No-Throw-Mechanismus, da ich nicht abstürzen möchte, wenn die API die Ordnergröße nicht abrufen kann. Diese Methode ist nicht für Multithread-Szenarien geeignet.

Zunächst möchte ich beim Durchlaufen des Dateisystembaums nach gültigen Verzeichnissen suchen.

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

Zweitens möchte ich nicht, dass mein rekursiver Aufruf in Symlinks (Softlinks) übergeht und die Größe in das Gesamtaggregat einbezieht.

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

Schließlich meine rekursionsbasierte Implementierung, um die Größe des angegebenen Verzeichnisses abzurufen. Beachten Sie die Nullprüfung für dir.listFiles (). Laut javadoc besteht die Möglichkeit, dass diese Methode null zurückgibt.

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

Etwas Sahne auf dem Kuchen, die API, um die Größe der Liste Dateien zu erhalten (möglicherweise alle Dateien und Ordner unter root).

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;
}
AB
quelle
0

unter linux wenn du verzeichnisse sortieren willst dann du -hs * | sort -h

Prem S.
quelle
0

Sie können verwenden Apache Commons IO, um die Ordnergröße leicht zu finden.

Wenn Sie auf Maven sind, fügen Sie bitte die folgende Abhängigkeit in Ihre pom.xmlDatei ein.

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

Wenn Sie kein Fan von Maven sind, laden Sie das folgende Glas herunter und fügen Sie es dem Klassenpfad hinzu.

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
}

Um die Dateigröße über Commons IO zu erhalten,

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

long fileSize = FileUtils.sizeOf(file);

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

Es ist auch über erreichbar Google Guava

Fügen Sie für Maven Folgendes hinzu:

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

Wenn Sie Maven nicht verwenden, fügen Sie dem Klassenpfad Folgendes hinzu

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

Um die Dateigröße zu erhalten,

 File file = new File("PATH TO YOUR FILE");
 long s  = file.length();
 System.out.println(s);
Dulith De Costa
quelle
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;
        }
Jaskaran Singh
quelle
Obwohl Ihr Code gut aussieht, bin ich mir nicht sicher, ob er den anderen Antworten etwas hinzufügt. Wenn dies der Fall ist, bearbeiten Sie bitte Ihre Antwort, um dies zu erklären.
Dragon Thoughts
Es ist nur eine aktualisierte Version, in der derselbe Job in weniger Codezeilen ausgeführt wird.
Jaskaran Singh