Obtenir la taille du dossier ou du fichier

105

Comment puis-je récupérer la taille du dossier ou du fichier en Java?

une place
la source
Idem mais avec un accent sur l'efficacité: stackoverflow.com/questions/116574/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
Si vous êtes sur Android, jetez un œil à StatFs. Il utilise les statistiques du système de fichiers et est presque 1000 fois plus rapide que les méthodes récursives, qui étaient inutilisables pour nos besoins. Notre implémentation peut être trouvée ici: stackoverflow.com/a/58418639/293280
Joshua Pinter

Réponses:

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

Cela renvoie la longueur du fichier en octets ou 0si le fichier n'existe pas. Il n'y a pas de moyen intégré pour obtenir la taille d'un dossier, vous allez devoir parcourir l'arborescence de répertoires de manière récursive (en utilisant la listFiles()méthode d'un objet fichier qui représente un répertoire) et accumuler la taille du répertoire pour vous-même:

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

AVERTISSEMENT : cette méthode n'est pas suffisamment robuste pour une utilisation en production. directory.listFiles()peut revenir nullet provoquer un NullPointerException. De plus, il ne prend pas en compte les liens symboliques et possède éventuellement d'autres modes d'échec. Utilisez cette méthode .

Tendayi Mawushe
la source
11
Soyez prudent si vous exécutez ceci dans le répertoire racine C: sur une machine Windows; il y a là un fichier système qui n'est (selon java.io.File) ni un fichier ni un répertoire. Vous souhaiterez peut-être modifier la clause else pour vérifier que le fichier est bien un répertoire.
Paul Clapham
2
Changement simple pour vérifier le paramètre pour voir s'il ne s'agit pas d'un répertoire au début de la méthode et renvoyer la longueur, la récursivité est plus simple - ajoutez simplement l'appel à self dans la même méthode et cela prend en charge le passage d'une référence de fichier à la place d'un annuaire également.
Kevin Brock
3
Si vous utilisez Java 7 ou supérieur, utilisez la réponse stackoverflow.com/a/19877372/40064, c'est beaucoup plus rapide.
Wim Deblauwe du
1
Cela sera confondu par les liens symboliques. En outre, il peut lancer un NullPointerExceptionsi le répertoire est modifié simultanément.
Aleksandr Dubinsky
43

En utilisant java-7 nio api, le calcul de la taille du dossier peut être fait beaucoup plus rapidement.

Voici un exemple prêt à l'emploi qui est robuste et ne lèvera pas d'exception. Il enregistrera les répertoires qu'il ne peut pas entrer ou qu'il a eu du mal à parcourir. Les liens symboliques sont ignorés et la modification simultanée du répertoire ne causera pas plus de problèmes que nécessaire.

/**
 * 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
la source
Y a-t-il un équivalent pour cela sur le développement Android?
développeur android
Y a-t-il une raison d'utiliser AtomicLongau lieu de simplement long?
Lukas Schmelzeisen
La variable doit être définitive lorsqu'elle est accessible depuis une classe anonyme
Aksel Willgert
1
J'ai fait un benchmark en utilisant JMH et cette méthode api NIO est environ 4 à 5 fois plus rapide par rapport au code commons-io (testé sur un dossier avec de nombreux sous-dossiers pour un total de 180229 fichiers). Commons IO a pris 15 secondes, NIO a pris 5 secondes.
Wim Deblauwe
3
Cette approche est la plus robuste. Il traite des liens symboliques, des modifications simultanées, des exceptions de sécurité, fonctionne à la fois avec des fichiers et des répertoires, etc. C'est dommage de Filesne pas le supporter directement!
Aleksandr Dubinsky
38

Vous avez besoin FileUtils#sizeOfDirectory(File)de commons-io .

Notez que vous devrez vérifier manuellement si le fichier est un répertoire car la méthode lève une exception si un non-répertoire lui est passé.

AVERTISSEMENT : cette méthode (à partir de commons-io 2.4) a un bogue et peut lancer IllegalArgumentExceptionsi le répertoire est modifié simultanément.

yegor256
la source
Alors, que se passe-t-il lorsque le fichier n'est pas un répertoire? quand ça n'existe pas? etc - how awful docs
Mr_and_Mrs_D
@Mr_and_Mrs_D - Copiez et collez simplement les lignes après la checkDirectory(directory);vérification. Assurez-vous simplement que cela File.listFilesa des enfants. Réf : FileUtils.sizeOfDirectory () , File.listFiles ()
Mr. Polywhirl
3
Voir le bogue IO-449 . Cette méthode lèvera un IllegalArgumentExceptionsi le répertoire est modifié pendant son itération.
Aleksandr Dubinsky
Aie!!! Ça craint ... ouais, ça répertorie les fichiers et puis si on est supprimé pendant que le code est en cours d'exécution, ça jette.
Dean Hiller
19

Dans Java 8:

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

Ce serait plus agréable à utiliser Files::sizedans l'étape de la carte mais cela lève une exception vérifiée.

MISE À JOUR:
Vous devez également être conscient que cela peut lever une exception si certains des fichiers / dossiers ne sont pas accessibles. Voir cette question et une autre solution utilisant Guava .

Andrejs
la source
1
Je cherchais quelque chose de similaire et je me suis retrouvé avec le code en question: stackoverflow.com/questions/22867286/ ... , comme vous le voyez, il y a un autre aspect de la gestion des erreurs qui pose également des problèmes.
Aksel Willgert
@AkselWillgert Merci, c'est malheureux et j'ai mis à jour la réponse. Passage maintenant à 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
la source
1
@Vishal, votre code doit avoir un correctif simple, dans l'appel récursif, vous devez ajouter la taille à la taille existante et non seulement lui attribuer. size += getFolderSize(file);
Teja Kantamneni du
@Teja: Merci de l'avoir signalé, mais les changements seront également dans la déclaration if
Vishal
Parfois, sur un dossier en croissance (un autre thread télécharge des fichiers et des dossiers et en même temps j'imprime la taille du dossier au fur et à mesure de la progression), il donne nullpointerexception à la ligne "for (File file: dir.listFiles ()) {". Certains fichiers apparaissent et disparaissent rapidement dans un dossier vivant. J'ai donc ajouté une vérification nulle pour la valeur de retour de dir.listFiles () avant la boucle for.
csonuryilmaz
De File.listFiles () javadoc: "Le tableau sera vide si le répertoire est vide. Renvoie null si ce chemin abstrait ne désigne pas un répertoire, ou si une erreur d'E / S se produit." Le commentaire ci-dessus est donc utile pour obtenir la taille du dossier sur des dossiers à changement dynamique.
csonuryilmaz
7

Pour Java 8, c'est une bonne façon de le faire:

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

Il est important de filtrer tous les répertoires , car la méthode de longueur n'est pas garantie à 0 pour les répertoires.

Au moins, ce code fournit les mêmes informations de taille que l'Explorateur Windows lui-même.

wumpz
la source
4

Voici le meilleur moyen d'obtenir la taille générale d'un fichier (fonctionne pour les répertoires et les non-répertoires):

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

Edit: Notez que cela va probablement être une opération longue. Ne l'exécutez pas sur le thread de l'interface utilisateur.

En outre, ici (extrait de https://stackoverflow.com/a/5599842/1696171 ) est un bon moyen d'obtenir une chaîne lisible par l'utilisateur à partir du long renvoyé:

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
la source
4

Si vous souhaitez utiliser l' API Java 8 NIO , le programme suivant imprimera la taille, en octets, du répertoire dans lequel il se trouve.

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

}

La calculateSizeméthode est universelle pour les Pathobjets, elle fonctionne donc également pour les fichiers. Notez que si un fichier ou un répertoire est inaccessible, dans ce cas, la taille renvoyée de l'objet chemin sera 0.

dinomario10
la source
3

File.length()( Javadoc ).

Notez que cela ne fonctionne pas pour les répertoires ou n'est pas garanti.

Pour un annuaire, que voulez-vous? S'il s'agit de la taille totale de tous les fichiers en dessous, vous pouvez parcourir les enfants de manière récursive en utilisant File.list()et File.isDirectory()et additionner leurs tailles.

Danben
la source
3

L' Fileobjet a une lengthméthode:

f = new File("your/file/name");
f.length();
JesperE
la source
3
  • Fonctionne pour Android et Java
  • Fonctionne pour les dossiers et les fichiers
  • Vérifie le pointeur nul partout où cela est nécessaire
  • Ignore le lien symbolique aka les raccourcis
  • Production prête!

Code source:

   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
la source
1

pour windows, en utilisant java.io cette fonction récursive est utile.

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

Ceci est testé et fonctionne correctement de mon côté.

C'est PD
la source
1

J'ai testé du -c <folderpath>et est 2x plus rapide que nio.Files ou récursivité

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
la source
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;
    }
Nicolas
la source
0

Après de nombreuses recherches et recherches sur les différentes solutions proposées ici chez StackOverflow. J'ai finalement décidé d'écrire ma propre solution. Mon but est d'avoir un mécanisme de non-projection car je ne veux pas planter si l'API est incapable de récupérer la taille du dossier.Cette méthode ne convient pas aux scénarios multithreads.

Tout d'abord, je veux vérifier les répertoires valides tout en parcourant l'arborescence du système de fichiers.

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

Deuxièmement, je ne veux pas que mon appel récursif entre dans des liens symboliques (liens souples) et inclue la taille dans l'agrégat total.

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

Enfin, mon implémentation basée sur la récursivité pour récupérer la taille du répertoire spécifié. Notez la vérification nulle pour dir.listFiles (). Selon javadoc, il est possible que cette méthode puisse retourner 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;
    }
}

Un peu de crème sur le gâteau, l'API pour obtenir la taille de la liste des fichiers (peut-être tous les fichiers et dossiers sous la racine).

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;
}
UN B
la source
0

sous linux si vous voulez trier les répertoires, alors du -hs * | trier -h

Prem S
la source
0

Vous pouvez utiliser Apache Commons IO pour trouver facilement la taille du dossier.

Si vous êtes sur maven, veuillez ajouter la dépendance suivante dans votre pom.xmlfichier.

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

Si vous n'êtes pas fan de Maven, téléchargez le fichier jar suivant et ajoutez-le au chemin de classe.

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
}

Pour obtenir la taille du fichier via Commons IO,

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

long fileSize = FileUtils.sizeOf(file);

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

Il est également réalisable via Google Guava

Pour Maven, ajoutez ce qui suit:

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

Si vous n'utilisez pas Maven, ajoutez ce qui suit au chemin de classe

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

Pour obtenir la taille du fichier,

 File file = new File("PATH TO YOUR FILE");
 long s  = file.length();
 System.out.println(s);
Dulith De Costa
la source
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
la source
Bien que votre code semble bon, je ne suis pas sûr qu'il ajoute quelque chose aux autres réponses. Si tel est le cas, veuillez modifier votre réponse pour expliquer.
Dragonthoughts
C'est juste une version mise à jour de faire le même travail en moins de lignes de code.
Jaskaran Singh