2010-10-28 8 views
25

Ist es möglich, einfach die Größe eines Ordners auf der SD-Karte zu erhalten? Ich verwende einen Ordner zum Zwischenspeichern von Bildern und möchte die Gesamtgröße aller zwischengespeicherten Bilder darstellen. Gibt es einen anderen Weg als über jede Datei zu iterieren? Sie alle befinden sich in demselben Ordner?Wie bekomme ich die Größe eines Ordners auf SD-Karte in Android?

Antwort

35

Gehen Sie einfach durch alle Dateien und die Summe der Länge von ihnen:

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

HINWEIS: Funktion von Hand geschrieben, so kann es nicht kompilieren!

EDITED: rekursiver Aufruf behoben.

EDITED: dirList.length wurde in fileList.length geändert.

+0

Sie könnten findFile durch dirSize ersetzen :) –

+0

Ich empfehle, 'dir.exists()' durch 'dir.isDirectory()' zu ersetzen. Wenn eine Datei als Argument angegeben wird, wird aufgrund von listFiles() result eine NullPointerException ausgelöst. –

+0

@Moss Die "for-each" -Schleife ist besser, wie Google in http://developer.android.com/training/articles/perf-tips.html#Loops –

0

Iterieren durch alle Dateien ist weniger als 5 Zeilen Code und der einzige vernünftige Weg, dies zu tun. Wenn Sie hässlich erhalten möchten können Sie auch einen Systembefehl (Runtime.getRuntime() exec („du“).) Laufen und den Ausgang fangen;)

+1

Fair genug. Ich dachte nur, dass es so ein gewöhnlicher Anwendungsfall war, dass es eine native Lösung geben sollte. Faulheit ist gut ... Fünf Zeilen später, und ich bin glücklich :) –

+0

In Clojure: (defn dir-size [dir] (reduzieren + (map # (. Length%) (.listFiles (neue Datei dir))))) –

+0

Ich glaube nicht, dass es sicher ist, darauf zu vertrauen, dass du verfügbar und ausführbar bist. –

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

Da es sich um Dateioperationen handelt, ist es unwahrscheinlich, dass die Rekursion für einen Großteil des Leistungseinbruchs verantwortlich ist. Außerdem ist die Implementierung von java.util.Stack sehr langsam. Ich habe versucht, einen rekursiven Algorithmus damit zu optimieren, und es war tatsächlich langsamer, als dass die JVM ihren Job machen konnte. –

+0

java.util.Stack Klassenmethoden sind synchronisiert. Wenn Sie Rekursionen wirklich vermeiden möchten, ist es besser LinkedList zu verwenden. –

1

unten Methode Sie Größe des Ordners zurück: -

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

Aufruf oben Methode: -

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

long folder_size=getFolderSize(file); 

Rückkehr Sie Größe des Ordners.

3

Der Weg von #Moss ist richtig. Dies ist mein Code für diejenigen, die Bytes in ein für Menschen lesbares Format ändern wollen. Sie müssen nur Pfad des Ordners zu dirSize(String path) und bekommen für Menschen lesbaren Format auf Basis von Byte, Kilo, Mega und etc.

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

Problem mit anderen Lösung ist, dass sie Ihnen nur logische Größe aller Dateien in bestimmten zuweisen Verzeichnis. Es wird sich vom tatsächlichen (physischen) genutzten Raum unterscheiden. Wenn Ihr Verzeichnis viele Unterverzeichnisse und/oder kleine Dateien enthält, kann ein großer Unterschied zwischen der logischen und der tatsächlichen Größe des Verzeichnisses bestehen.

Hier ist, was ich gefunden habe, wie man physikalische Struktur von FS zu zählen.

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

können Sie StatFs verwenden Blockgröße zu erhalten:

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

Ich habe bemerkt, dass, wenn ich "length()" in einem Verzeichnis anrufe, ich nicht 0, sondern eine reelle Zahl bekomme. Ist es möglich, dass Sie anstelle von dem, was Sie getan haben, einfach "length()" in den Verzeichnissen verwenden können (und natürlich den Rest hinzufügen - die Größe der normalen Dateien hinzufügen)? –

5

Sie diesen Code verwenden sollten der logischen Größe:

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

Tolle Lösung für mich, ich habe einen Ordner mit einigen Audiodateien und es funktioniert perfekt für mich! (Ich habe keine Unterordner in diesem Ordner!) – basti12354

11

Hier einige Code, der Rekursion vermeidet, und berechnet auch die physikalische Größe statt:

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

das ist absolut richtige Antwort für die Berechnung der Größe von Datei/Ordner –

+0

Ich war eigentlich überrascht zu sehen, dass (auf Android) jeder Ordner etwa 4KB dauert, auch wenn es leer ist. frage mich, warum sie es so gemacht haben. –

+0

@androiddeveloper Es ist die Sektorgröße. Sie werden feststellen, dass das gleiche auf jedem Desktop-Betriebssystem zutrifft. –

0

Sie können MediaStore nach einer Verzeichnisgröße im internen Speicher abfragen. Dies ist viel schneller als eine rekursive Methode, die die Länge jeder Datei in einem Verzeichnis ermittelt. Sie müssen die Berechtigung READ_EXTERNAL_STORAGE haben.

Beispiel:

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

Output:

/storage/emulierten/0/DCIM 30,86 MB

Verwandte Themen