E 'possibile ottenere facilmente le dimensioni di una cartella sulla scheda SD? Uso una cartella per la memorizzazione nella cache delle immagini e desidero presentare la dimensione totale di tutte le immagini memorizzate nella cache. C'è un modo per questo oltre a iterare su ogni file? Risiedono tutte all'interno della stessa cartella?Come posso ottenere la dimensione di una cartella su scheda SD in Android?
risposta
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.
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;)
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 :) –
In Clojure: (defn dir-size [dir] (riduci + (map # (. Length%) (.listFiles (new File dir))))) –
Non penso che sia possibile fare affidamento sul fatto che sia disponibile ed eseguibile. –
/**
* 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;
}
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. –
java.util.Stack i metodi di classe sono sincronizzati. Se vuoi davvero evitare la ricorsione, è meglio usare LinkedList. –
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.
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;
}
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);
}
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)? –
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;
}
Ottima soluzione per me, sto avendo una cartella con alcuni file audio e funziona perfettamente per me! (Non ho sottocartelle in questa cartella!) – basti12354
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;
}
questa è assolutamente la risposta giusta per il calcolo della dimensione di FILE/FOLDER –
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. –
@androiddeveloper È la dimensione del settore. Noterai che lo stesso vale per qualsiasi sistema operativo desktop. –
È 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
Si potrebbe voler sostituire findFile da dirSize :) –
suggerisco di sostituire 'dir.exists()' con 'dir.isDirectory()'. se un file viene fornito come argomento, NullPointerException viene generato a causa del risultato listFiles(). –
@Moss Il ciclo "for-each" è migliore, come suggerito da Google in http://developer.android.com/training/articles/perf-tips.html#Loops –