2010-10-28 36 views
25

Có thể dễ dàng lấy kích thước của một thư mục trên thẻ SD không? Tôi sử dụng một thư mục cho bộ nhớ đệm của hình ảnh, và muốn trình bày tổng kích thước của tất cả các hình ảnh được lưu trữ. Có cách nào khác hơn là lặp qua mỗi tập tin? Tất cả chúng đều nằm trong cùng một thư mục?Làm thế nào tôi có thể nhận được kích thước của một thư mục trên thẻ SD trong Android?

Trả lời

35

Chỉ cần đi qua tất cả các file và tổng chiều dài của họ:

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

Chú ý: Chức năng viết bằng tay nên không thể biên dịch!

CHỈNH SỬA: cuộc gọi đệ quy đã được sửa.

CHỈNH SỬA: dirList.length đổi thành fileList.length.

+0

Bạn có thể muốn thay thế findFile bằng dirSize :) –

+0

tôi đề nghị thay thế 'dir.exists()' bằng 'dir.isDirectory()'. nếu một tập tin được đưa ra như là đối số NullPointerException được ném do kết quả listFiles(). –

+0

@Moss Vòng lặp "cho mỗi" là tốt hơn, như Google đề xuất trong http://developer.android.com/training/articles/perf-tips.html#Loops –

0

Lặp lại tất cả các tệp có ít hơn 5 dòng mã và cách hợp lý duy nhất để thực hiện việc này. Nếu bạn muốn nhận được xấu xí bạn cũng có thể chạy một lệnh hệ thống (Runtime.getRuntime() exec ("du");.) Và bắt đầu ra;)

+1

Đủ công bằng. Chỉ cần tìm ra nó là một trường hợp sử dụng phổ biến mà cần phải có một số giải pháp bản địa. Sự tốt lành là tốt ... Năm dòng sau, và tôi hạnh phúc :) –

+0

Trong Clojure: (defn dir-size [dir] (giảm + (bản đồ # (. Length%) (.listFiles (thư mục File mới))))) –

+0

Tôi không nghĩ rằng nó an toàn để dựa vào việc có sẵn và thực thi. –

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

Vì chúng ta đang nói về các thao tác tệp, đệ quy không có khả năng chiếm phần lớn hiệu suất truy cập. Ngoài ra, việc thực hiện java.util.Stack là rất chậm. Tôi đã cố gắng tối ưu hóa một thuật toán đệ quy với nó và nó thực sự chậm hơn sau đó để cho JVM thực hiện công việc của mình. –

+0

java.util.Phương thức lớp học đã được đồng bộ hóa. Nếu bạn thực sự muốn tránh đệ quy thì tốt hơn nên sử dụng LinkedList. –

1

dưới phương pháp trả lại cho bạn kích thước của thư mục: -

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

gọi phương pháp nêu trên: -

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

long folder_size=getFolderSize(file); 

bù lại bạn kích thước của thư mục.

3

Cách của #Moss là đúng. Đây là mã của tôi cho những ai muốn thay đổi byte thành định dạng có thể đọc được của con người. Bạn chỉ cần gán con đường của thư mục của bạn để dirSize(String path) và nhận dạng có thể đọc được con người dựa trên byte, kg, mega và vv

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

Vấn đề với giải pháp khác là họ cung cấp cho bạn chỉ kích thước hợp lý của tất cả các tập tin trong định danh mục. Nó sẽ khác với không gian sử dụng thực tế (vật lý). Nếu thư mục của bạn có rất nhiều thư mục con và/hoặc các tệp nhỏ, có thể có sự khác biệt lớn giữa kích thước thư mục và kích thước thực tế.

Dưới đây là những gì tôi đã tìm hiểu cách tính số lượng cấu trúc vật lý của 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; 
    } 
} 

Bạn có thể sử dụng StatFs để có được kích thước khối:

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

Tôi nhận thấy rằng nếu tôi gọi "length()" trên một thư mục, tôi không nhận được 0, nhưng là một số thực. Có thể là thay vì sử dụng những gì bạn đã làm, bạn chỉ có thể sử dụng "length()" trên các thư mục (và tất nhiên làm phần còn lại thêm kích thước của các tập tin bình thường)? –

5

bạn nên sử dụng mã này:

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

Giải pháp tuyệt vời cho tôi, tôi đang có một thư mục với một số tập tin âm thanh và nó hoạt động perfekt cho tôi! (Tôi không có thư mục con nào trong thư mục này!) – basti12354

11

Dưới đây là một số mã mà tránh đệ quy, và cũng có thể tính toán kích thước vật lý thay vì có kích thước lôgic:

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

đây là câu trả lời hoàn toàn đúng để tính toán kích thước của FILE/FOLDER –

+0

Tôi thực sự ngạc nhiên khi thấy rằng (trên Android) mỗi thư mục mất khoảng 4KB ngay cả khi nó trống. tự hỏi tại sao họ lại làm theo cách này. –

+0

@androiddeveloper Đó là quy mô ngành. Bạn sẽ nhận thấy rằng điều này cũng đúng trên bất kỳ hệ điều hành máy tính để bàn nào. –

0

Bạn có thể truy vấn MediaStore cho kích thước thư mục trên bộ nhớ trong. Điều này là nhanh hơn nhiều so với một phương pháp đệ quy nhận được chiều dài của mỗi tập tin trong một thư mục. Bạn phải có sự cho phép READ_EXTERNAL_STORAGE.

Ví dụ:

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

Cách sử dụng:

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

Output:

/lưu trữ/mô phỏng/0/DCIM 30.86 MB

Các vấn đề liên quan