2010-10-28 30 views

Respuesta

35

Sólo tienes que ir a través de todos los archivos y la suma de la longitud de ellos:

/** 
* 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: Función escrito a mano por lo que no podría compilar!

EDITADO: llamada recursiva fija.

EDITADO: dirList.length cambiado a fileList.length.

+0

Es posible que desee reemplazar findFile por dirSize :) –

+0

sugiero reemplazar 'dir.exists()' con 'dir.isDirectory()'. si un archivo se da como argumento, se lanza NullPointerException debido al resultado de listFiles(). –

+0

@Moss El ciclo "para-cada uno" es mejor, como Google sugiere en http://developer.android.com/training/articles/perf-tips.html#Loops –

0

Iterar a través de todos los archivos es menos de 5 líneas de código y la única forma razonable de hacerlo. Si desea ponerse feo también se puede ejecutar un comando del sistema (Runtime.getRuntime() exec ("du");.) Y coger la salida;)

+1

Lo suficiente. Pensé que era un caso de uso tan común que debería haber alguna solución nativa. La pereza es buena ... Cinco líneas después, y estoy feliz :) –

+0

En Clojure: (defn dir-size [dir] (reduce + (map # (. Length%) (.listFiles (nuevo File dir))))) –

+0

No creo que sea seguro confiar en que esté disponible y ejecutable. –

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

Como estamos hablando de operaciones de archivos, es poco probable que la recursividad represente gran parte del rendimiento alcanzado. Además, la implementación de java.util.Stack es muy lenta. Traté de optimizar un algoritmo recursivo con él y en realidad fue más lento que dejar que la JVM hiciera su trabajo. –

+0

java.util.Los métodos de clase de pila están sincronizados. Si realmente desea evitar la recursividad, es mejor utilizar LinkedList. –

1

debajo método retorno que el tamaño de la carpeta: -

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

llamada anterior método: -

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

long folder_size=getFolderSize(file); 

que regreso tamaño de la carpeta.

3

El camino de #Moss es correcto. Este es mi código para aquellos que quieren cambiar los bytes a un formato legible por humanos. Sólo tiene que asignar ruta de la carpeta para dirSize(String path) y obtener formato legible por humanos basado en bytes, kilo, mega y 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

Problema con otra solución es que te proporcionan solamente tamaño lógico de todos los archivos especificados directorio. Será diferente del espacio utilizado real (físico). Si su directorio tiene muchos subdirectorios y/o archivos pequeños, puede haber una gran diferencia entre el tamaño lógico y el tamaño real del directorio.

Esto es lo que encontré cómo tener en cuenta la estructura física de 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; 
    } 
} 

Puede utilizar StatFs para obtener el tamaño de bloque:

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

Me he dado cuenta de que si llamo "length()" en un directorio, no obtengo 0, sino un número real. ¿Es posible que en lugar de usar lo que has hecho, simplemente puedas usar "length()" en los directorios (y por supuesto, hacer el resto, agregar el tamaño de los archivos normales)? –

5

se debe utilizar este código:

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

¡Gran solución para mí, tengo una carpeta con algunos archivos de audio y funciona perfectamente para mí! (No tengo ninguna subcarpeta en esta carpeta!) – basti12354

11

Aquí hay un código que evite la repetición, y también calcula el tamaño físico vez del tamaño lógico:

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

esta es la respuesta correcta para calcular el tamaño de ARCHIVO/CARPETA –

+0

De hecho, me sorprendió ver que (en Android) cada carpeta tarda unos 4 KB incluso cuando está vacía. Me pregunto por qué lo hicieron de esta manera. –

+0

@androiddeveloper Es el tamaño del sector. Notarás que lo mismo es cierto en cualquier sistema operativo de escritorio. –

0

Puede consultar MediaStore para obtener un tamaño de directorio en el almacenamiento interno. Esto es mucho más rápido que un método recursivo para obtener la longitud de cada archivo en un directorio. Debe tener el permiso READ_EXTERNAL_STORAGE otorgado.

Ejemplo:

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

Uso:

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

de salida:

/almacenamiento/emulado/0/DCIM 30,86 MB

Cuestiones relacionadas