2010-10-28 15 views

risposta

35

Basta passare attraverso tutti i file e la somma della lunghezza di loro:

/** 
* Return the size of a directory in bytes 
*/ 
private static long dirSize(File dir) { 

    if (dir.exists()) { 
     long result = 0; 
     File[] fileList = dir.listFiles(); 
     for(int i = 0; i < fileList.length; i++) { 
      // Recursive call if it's a directory 
      if(fileList[i].isDirectory()) { 
       result += dirSize(fileList [i]); 
      } else { 
       // Sum the file size in bytes 
       result += fileList[i].length(); 
      } 
     } 
     return result; // return the file size 
    } 
    return 0; 
} 

NOTA: funzione scritta a mano in modo che non poteva compilare!

MODIFICATO: chiamata ricorsiva fissa.

MODIFICATO: dirList.length cambiato in fileList.length.

+0

Si potrebbe voler sostituire findFile da dirSize :) –

+0

suggerisco di sostituire 'dir.exists()' con 'dir.isDirectory()'. se un file viene fornito come argomento, NullPointerException viene generato a causa del risultato listFiles(). –

+0

@Moss Il ciclo "for-each" è migliore, come suggerito da Google in http://developer.android.com/training/articles/perf-tips.html#Loops –

0

L'iterazione di tutti i file è inferiore a 5 righe di codice e l'unico modo ragionevole per farlo. Se si desidera ottenere brutto si potrebbe anche eseguire un comando di sistema (Runtime.getRuntime() exec ("du");.) E prendere l'uscita;)

+1

Abbastanza corretto. Immaginavo che fosse un caso di uso comune che ci fosse una soluzione nativa. La pigrizia è buona ... Cinque righe dopo, e sono felice :) –

+0

In Clojure: (defn dir-size [dir] (riduci + (map # (. Length%) (.listFiles (new File dir))))) –

+0

Non penso che sia possibile fare affidamento sul fatto che sia disponibile ed eseguibile. –

5
/** 
* Try this one for better performance 
* Mehran 
* Return the size of a directory in bytes 
**/ 

private static long dirSize(File dir) { 
    long result = 0; 

    Stack<File> dirlist= new Stack<File>(); 
    dirlist.clear(); 

    dirlist.push(dir); 

    while(!dirlist.isEmpty()) 
    { 
     File dirCurrent = dirlist.pop(); 

     File[] fileList = dirCurrent.listFiles(); 
     for(File f: fileList){ 
      if(f.isDirectory()) 
       dirlist.push(f); 
      else 
       result += f.length(); 
     } 
    } 

    return result; 
} 
+2

Dato che stiamo parlando di operazioni sui file, è improbabile che la ricorsione tenga conto di gran parte delle prestazioni. Inoltre, l'implementazione java.util.Stack è molto lenta. Ho provato ad ottimizzare un algoritmo ricorsivo con esso ed è stato effettivamente più lento quindi lasciare che la JVM faccia il suo lavoro. –

+0

java.util.Stack i metodi di classe sono sincronizzati. Se vuoi davvero evitare la ricorsione, è meglio usare LinkedList. –

1

di seguito il metodo di ritorno si dimensione della cartella: -

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

chiamata di metodo di cui sopra: -

File file = new File(Environment.getExternalStorageDirectory().getPath()+"/urfoldername/"); 

long folder_size=getFolderSize(file); 

cambio si dimensione della cartella.

3

Il modo in cui #Moss è giusto. Questo è il mio codice per coloro che vogliono cambiare i byte in un formato leggibile. Hai solo bisogno di assegnare il percorso della cartella per dirSize(String path) e ottenere un formato leggibile sulla base di byte, chilo, mega ecc

private static String dirSize(String path) { 

     File dir = new File(path); 

     if(dir.exists()) { 
      long bytes = getFolderSize(dir); 
      if (bytes < 1024) return bytes + " B"; 
      int exp = (int) (Math.log(bytes)/Math.log(1024)); 
      String pre = ("KMGTPE").charAt(exp-1) + ""; 

      return String.format("%.1f %sB", bytes/Math.pow(1024, exp), pre); 
     } 

     return "0"; 
    } 

    public static long getFolderSize(File dir) { 
     if (dir.exists()) { 
      long result = 0; 
      File[] fileList = dir.listFiles(); 
      for(int i = 0; i < fileList.length; i++) { 
       // Recursive call if it's a directory 
       if(fileList[i].isDirectory()) { 
        result += getFolderSize(fileList[i]); 
       } else { 
        // Sum the file size in bytes 
        result += fileList[i].length(); 
       } 
      } 
      return result; // return the file size 
     } 
     return 0; 
    } 
2

problema con altra soluzione è che essi forniscono solo dimensione logica di tutti i file in specificato directory. Sarà diverso dallo spazio reale (fisico) usato. Se la directory contiene molte sottodirectory e/o file di piccole dimensioni, potrebbe esserci un'enorme differenza tra la dimensione logica e quella effettiva della directory.

Ecco cosa ho trovato come prendere in considerazione la struttura fisica di FS.

public static long getDirectorySize(File directory, long blockSize) { 
    File[] files = directory.listFiles(); 
    if (files != null) { 

     // space used by directory itself 
     long size = file.length(); 

     for (File file : files) { 
      if (file.isDirectory()) { 
       // space used by subdirectory 
       size += getDirectorySize(file, blockSize); 
      } else { 
       // file size need to rounded up to full block sizes 
       // (not a perfect function, it adds additional block to 0 sized files 
       // and file who perfectly fill their blocks) 
       size += (file.length()/blockSize + 1) * blockSize; 
      } 
     } 
     return size; 
    } else { 
     return 0; 
    } 
} 

È possibile utilizzare StatFs per ottenere la dimensione del blocco:

public static long getDirectorySize(File directory) { 
    StatFs statFs = new StatFs(directory.getAbsolutePath()); 
    long blockSize; 
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { 
     blockSize = statFs.getBlockSizeLong() 
    } else { 
     blockSize = statFs.getBlockSize(); 
    } 

    return getDirectorySize(directory, blockSize); 
} 
+0

Ho notato che se chiamo "length()" su una directory, non ottengo 0, ma un numero reale. È possibile che invece di usare quello che hai fatto tu possa semplicemente usare "length()" nelle directory (e naturalmente fare il resto - aggiungendo la dimensione dei file normali)? –

5

si dovrebbe usare questo codice:

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

Ottima soluzione per me, sto avendo una cartella con alcuni file audio e funziona perfettamente per me! (Non ho sottocartelle in questa cartella!) – basti12354

11

Ecco un po 'di codice che evita ricorsione, e calcola anche la dimensione fisica, invece delle dimensioni logiche:

public static long getFileSize(final File file) { 
    if (file == null || !file.exists()) 
     return 0; 
    if (!file.isDirectory()) 
     return file.length(); 
    final List<File> dirs = new LinkedList<>(); 
    dirs.add(file); 
    long result = 0; 
    while (!dirs.isEmpty()) { 
     final File dir = dirs.remove(0); 
     if (!dir.exists()) 
      continue; 
     final File[] listFiles = dir.listFiles(); 
     if (listFiles == null || listFiles.length == 0) 
      continue; 
     for (final File child : listFiles) { 
      result += child.length(); 
      if (child.isDirectory()) 
       dirs.add(child); 
     } 
    } 
    return result; 
} 
+0

questa è assolutamente la risposta giusta per il calcolo della dimensione di FILE/FOLDER –

+0

Sono stato davvero sorpreso di vedere che (su Android) ogni cartella impiega circa 4KB anche quando è vuota. chiedo perché l'abbiano fatto in questo modo. –

+0

@androiddeveloper È la dimensione del settore. Noterai che lo stesso vale per qualsiasi sistema operativo desktop. –

0

È possibile interrogare MediaStore per una dimensione di directory nella memoria interna. Questo è molto più veloce di un metodo ricorsivo che ottiene la lunghezza di ogni file in una directory. È necessario disporre dell'autorizzazione READ_EXTERNAL_STORAGE concessa.

Esempio:

/** 
* Query the media store for a directory size 
* 
* @param context 
*  the application context 
* @param file 
*  the directory on primary storage 
* @return the size of the directory 
*/ 
public static long getFolderSize(Context context, File file) { 
    File directory = readlink(file); // resolve symlinks to internal storage 
    String path = directory.getAbsolutePath(); 
    Cursor cursor = null; 
    long size = 0; 
    try { 
    cursor = context.getContentResolver().query(MediaStore.Files.getContentUri("external"), 
     new String[]{MediaStore.MediaColumns.SIZE}, 
     MediaStore.MediaColumns.DATA + " LIKE ?", 
     new String[]{path + "/%/%"}, 
     null); 
    if (cursor != null && cursor.moveToFirst()) { 
     do { 
     size += cursor.getLong(0); 
     } while (cursor.moveToNext()); 
    } 
    } finally { 
    if (cursor != null) { 
     cursor.close(); 
    } 
    } 
    return size; 
} 

/** 
* Canonicalize by following all symlinks. Same as "readlink -f file". 
* 
* @param file 
*  a {@link File} 
* @return The absolute canonical file 
*/ 
public static File readlink(File file) { 
    File f; 
    try { 
    f = file.getCanonicalFile(); 
    } catch (IOException e) { 
    return file; 
    } 
    if (f.getAbsolutePath().equals(file.getAbsolutePath())) { 
    return f; 
    } 
    return readlink(f); 
} 

Usage:

File DCIM = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM); 
long directorySize = getFolderSize(context, DCIM); 
String formattedSize = Formatter.formatFileSize(context, directorySize); 
System.out.println(DCIM + " " + formattedSize); 

uscita:

/stoccaggio/emulato/0/DCIM 30.86 MB