Ottieni la dimensione della cartella o del file


105

Come posso recuperare la dimensione della cartella o del file in Java?



Se ti trovi su Android, dai un'occhiata a StatFs. Utilizza le statistiche del file system ed è quasi 1000 volte più veloce dei metodi ricorsivi, che erano inutilizzabili per le nostre esigenze. La nostra implementazione può essere trovata qui: stackoverflow.com/a/58418639/293280
Joshua Pinter

Risposte:


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

Ciò restituisce la lunghezza del file in byte o 0se il file non esiste. Non esiste un modo integrato per ottenere la dimensione di una cartella, dovrai percorrere l'albero delle directory in modo ricorsivo (utilizzando il listFiles()metodo di un oggetto file che rappresenta una directory) e accumulare la dimensione della directory per te stesso:

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

ATTENZIONE : questo metodo non è sufficientemente robusto per l'uso in produzione. directory.listFiles()può tornare nulle causare a NullPointerException. Inoltre, non considera i collegamenti simbolici e possibilmente ha altre modalità di errore. Usa questo metodo .


11
Fai attenzione se lo esegui nella directory C: root su una macchina Windows; c'è un file di sistema lì che (secondo java.io.File) non è né un file né una directory. Potresti voler cambiare la clausola else per verificare che il File sia effettivamente una directory.
Paul Clapham,

2
Semplice modifica per controllare il parametro per vedere se nonèuna directory all'inizio del metodo e restituire la lunghezza, quindi la ricorsione è più semplice: basta aggiungere la chiamata a self nello stesso metodo e quindi questo supporta il passaggio di un riferimento al file invece anche di una directory.
Kevin Brock

3
Se usi Java 7 o versioni successive, usa la risposta stackoverflow.com/a/19877372/40064 è molto più veloce.
Wim Deblauwe

1
Questo sarà confuso dai collegamenti simbolici. Inoltre, può generare un NullPointerExceptionse la directory viene modificata contemporaneamente.
Aleksandr Dubinsky

43

Utilizzando java-7 nio api, il calcolo delle dimensioni della cartella può essere eseguito molto più rapidamente.

Ecco un esempio pronto per l'esecuzione che è robusto e non genererà un'eccezione. Registrerà le directory che non può entrare o ha avuto problemi ad attraversare. I collegamenti simbolici vengono ignorati e la modifica simultanea della directory non causerà più problemi del necessario.

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

C'è un equivalente per questo nello sviluppo Android?
sviluppatore Android

C'è un motivo per usare AtomicLonginvece che solo long?
Lukas Schmelzeisen

La variabile deve essere definitiva quando si accede dalla classe anonima
Aksel Willgert

1
Ho fatto un benchmark utilizzando JMH e questo metodo api NIO è da 4 a 5 volte più veloce rispetto al codice commons-io (testato su una cartella con molte sottocartelle per un totale di 180229 file). Commons IO ha impiegato 15 secondi, NIO ha impiegato 5 secondi.
Wim Deblauwe,

3
Questo approccio è il più robusto. Si occupa di collegamenti simbolici, modifiche simultanee, eccezioni di sicurezza, funziona sia con file che con directory, ecc. Peccato che Filesnon lo supporti direttamente!
Aleksandr Dubinsky

38

Hai bisogno FileUtils#sizeOfDirectory(File)di commons-io .

Tieni presente che dovrai controllare manualmente se il file è una directory poiché il metodo genera un'eccezione se gli viene passata una non directory.

ATTENZIONE : Questo metodo (a partire da commons-io 2.4) ha un bug e può generare IllegalArgumentExceptionse la directory viene modificata contemporaneamente.


Allora cosa succede quando il file non è una directory? quando non esiste? ecc. - che documenti orribili
Mr_and_Mrs_D

@Mr_and_Mrs_D - Basta copiare e incollare le righe dopo il checkDirectory(directory);controllo. Assicurati solo che File.listFilesabbia dei bambini. Rif : FileUtils.sizeOfDirectory () , File.listFiles ()
Mr. Polywhirl

3
Vedi bug IO-449 . Questo metodo genererà un messaggio IllegalArgumentExceptionse la directory viene modificata durante l'iterazione.
Aleksandr Dubinsky

Ahia!!! Fa schifo ... sì, elenca i file e quindi se uno viene eliminato mentre il codice è in esecuzione, lancia.
Dean Hiller

19

In Java 8:

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

Sarebbe più bello da usare Files::sizenel passaggio della mappa ma genera un'eccezione controllata.

AGGIORNAMENTO:
Dovresti anche essere consapevole che questo può generare un'eccezione se alcuni file / cartelle non sono accessibili. Vedi questa domanda e un'altra soluzione usando Guava .


1
stavo cercando qualcosa di simile e sono finito con il codice in questione: stackoverflow.com/questions/22867286/… , come vedi c'è un altro aspetto della gestione degli errori che causa problemi.
Aksel Willgert

@AkselWillgert Grazie, è un peccato e ho aggiornato la risposta. Passaggio a 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;
}

1
@Vishal il tuo codice deve avere una semplice correzione, nella chiamata ricorsiva, dovresti aggiungere la dimensione alla dimensione esistente non solo assegnarla. size += getFolderSize(file);
Teja Kantamneni,

@Teja: Grazie per averlo sottolineato, ma le modifiche saranno anche nell'istruzione if
Vishal

A volte su una cartella in crescita (un altro thread sta scaricando file e cartelle e allo stesso tempo sto stampando la dimensione della cartella mentre avanza) dà nullpointerexception alla riga "for (File file: dir.listFiles ()) {". Alcuni file vengono visualizzati e scompaiono rapidamente in una cartella vivente. Quindi ho aggiunto un controllo nullo per il valore di ritorno di dir.listFiles () prima del ciclo.
csonuryilmaz

Da File.listFiles () javadoc: "L'array sarà vuoto se la directory è vuota. Restituisce null se questo percorso astratto non denota una directory o se si verifica un errore di I / O." Quindi il commento sopra è utile quando si ottiene la dimensione della cartella su cartelle che cambiano dinamicamente.
csonuryilmaz

7

Per Java 8 questo è un modo giusto per farlo:

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

È importante filtrare tutte le directory , poiché non è garantito che il metodo della lunghezza sia 0 per le directory.

Almeno questo codice fornisce le stesse informazioni sulla dimensione di Windows Explorer stesso.


4

Ecco il modo migliore per ottenere la dimensione di un file generale (funziona per directory e non directory):

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

Modifica: nota che probabilmente questa sarà un'operazione che richiede tempo. Non eseguirlo sul thread dell'interfaccia utente.

Inoltre, qui (tratto da https://stackoverflow.com/a/5599842/1696171 ) è un bel modo per ottenere una stringa leggibile dall'utente dal lungo restituito:

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

Se si desidera utilizzare Java 8 NIO API, il seguente programma stamperà la dimensione, in byte, della directory in cui si trova.

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

}

Il calculateSizemetodo è universale per gli Pathoggetti, quindi funziona anche per i file. Si noti che se un file o una directory è inaccessibile, in questo caso la dimensione restituita dell'oggetto percorso sarà 0.


3

File.length()( Javadoc ).

Nota che questo non funziona per le directory o non è garantito che funzioni.

Per una directory, cosa vuoi? Se è la dimensione totale di tutti i file sottostanti, puoi camminare ricorsivamente i bambini usando File.list()e File.isDirectory()e sommare le loro dimensioni.


3

L' Fileoggetto ha un lengthmetodo:

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

3
  • Funziona per Android e Java
  • Funziona sia per cartelle che per file
  • Controlla il puntatore nullo ovunque dove necessario
  • Ignora il collegamento simbolico noto anche come scorciatoie
  • Produzione pronta!

Codice sorgente:

   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

per Windows, utilizzando java.io questa funzione ricorsiva è 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;
}

Questo è testato e funziona correttamente da parte mia.


1

Ho provato du -c <folderpath>ed è 2 volte più veloce di nio.Files o ricorsione

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

Dopo molte ricerche e analisi delle diverse soluzioni proposte qui su StackOverflow. Alla fine ho deciso di scrivere la mia soluzione. Il mio scopo è quello di avere un meccanismo no-throw perché non voglio andare in crash se l'API non è in grado di recuperare la dimensione della cartella. Questo metodo non è adatto per scenari multithread.

Prima di tutto voglio verificare la presenza di directory valide mentre attraverso l'albero del file system.

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

Secondo, non voglio che la mia chiamata ricorsiva vada nei collegamenti simbolici (softlink) e includa la dimensione nell'aggregato totale.

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

Infine la mia implementazione basata sulla ricorsione per recuperare la dimensione della directory specificata. Notare il controllo null per dir.listFiles (). Secondo javadoc esiste la possibilità che questo metodo possa restituire 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 po 'di crema sulla torta, l'API per ottenere la dimensione dell'elenco File (potrebbe essere tutti i file e le cartelle sotto 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;
}

0

in linux se vuoi ordinare le directory allora du -hs * | sort -h


0

Puoi usare Apache Commons IO per trovare facilmente la dimensione della cartella.

Se sei su Maven, aggiungi la seguente dipendenza nel tuo pom.xmlfile.

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

Se non sei un fan di Maven, scarica il seguente jar e aggiungilo al percorso della 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
}

Per ottenere la dimensione del file tramite Commons IO,

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

long fileSize = FileUtils.sizeOf(file);

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

È realizzabile anche tramite Google Guava

Per Maven, aggiungi quanto segue:

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

Se non si utilizza Maven, aggiungere quanto segue al percorso di 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;
    }

Per ottenere la dimensione del file,

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

Sebbene il tuo codice abbia un bell'aspetto, non sono sicuro che aggiunga qualcosa alle altre risposte. In caso affermativo, modifica la risposta per spiegare.
Pensieri del drago

È solo una versione aggiornata di fare lo stesso lavoro in meno righe di codice.
Jaskaran Singh
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.