如何在 Android 中获取 SD 卡上文件夹的大小?

Posted

技术标签:

【中文标题】如何在 Android 中获取 SD 卡上文件夹的大小?【英文标题】:How can I get the size of a folder on SD card in Android? 【发布时间】:2011-05-01 18:04:19 【问题描述】:

是否可以轻松获取 SD 卡上文件夹的大小?我使用一个文件夹来缓存图像,并希望显示所有缓存图像的总大小。除了遍历每个文件之外,还有其他方法吗?它们都位于同一个文件夹中?

【问题讨论】:

【参考方案1】:

只需浏览所有文件并总结它们的长度:

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

    if (dir.exists()) 
        long result = 0;
        File[] fileList = dir.listFiles();
        if (fileList != null) 
            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;

注意:手工编写的函数,因此无法编译!

【讨论】:

你可能想用 dirSize 替换 findFile :) 我建议将dir.exists() 替换为dir.isDirectory()。如果将文件作为参数给出 NullPointerException,则由于 listFiles() 结果而引发。 @Moss “for-each”循环更好,就像 Google 在 developer.android.com/training/articles/perf-tips.html#Loops 中建议的那样 在循环之前检查文件列表是否为空【参考方案2】:

遍历所有文件的代码少于 5 行,这是唯一合理的方法。如果你想变得丑陋,你也可以运行系统命令 (Runtime.getRuntime().exec("du");) 并捕获输出 ;)

【讨论】:

很公平。只是认为这是一个如此常见的用例,应该有一些本机解决方案。懒惰是好的......五行之后,我很高兴:) 在 Clojure 中:(defn dir-size [dir] (reduce + (map #(.length %) (.listFiles (new File dir))))) 我认为依赖 du 可用和可执行是不安全的。 究竟是如何触发“du”命令的?我试过 - Runtime.getRuntime().exec("/system/bin/du -b -d1 "+dir.getCanonicalPath(), new String[], Environment.getRootDirectory()); 没用。也没有 - (Runtime.getRuntime().exec("du"))【参考方案3】:
/**
 * 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;

【讨论】:

既然我们讨论的是文件操作,递归不太可能对性能造成很大影响。此外,java.util.Stack 实现非常慢。我试图用它来优化递归算法,但实际上它比让 JVM 完成它的工作要慢。 java.util.Stack 类方法是同步的。如果你真的想避免递归,最好使用 LinkedList。【参考方案4】:

下面的方法返回文件夹的大小:-

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;

调用上述方法:-

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

long folder_size=getFolderSize(file);

返回文件夹的大小。

【讨论】:

【参考方案5】:

#Moss 的方式是对的。这是我为那些想要将字节更改为人类可读格式的人的代码。您只需将文件夹的路径分配给dirSize(String path) 并获得基于字节、公斤、兆等的人类可读格式。

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;
     

【讨论】:

嗯,这是另一个关于可读性的问题,所以答案很离题【参考方案6】:

其他解决方案的问题是它们只为您提供指定目录中所有文件的逻辑大小。它将与实际(物理)使用空间不同。如果您的目录有很多子目录和/或小文件,则目录的逻辑大小和实际大小可能会有很大差异。

这是我发现的如何计算 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;
    

您可以使用StatFs 获取块大小:

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

【讨论】:

我注意到,如果我在目录上调用“length()”,我得到的不是 0,而是一个实数。是否有可能不使用你所做的,而只是在目录上使用“length()”(当然剩下的就是添加普通文件的大小)? 你的意思是return getDirectorySize(directory, blockSize); 只是return blockSize 非常感谢您提供这个答案。这是我们对StatFs 的第一次介绍,这正是我们所需要的。在大而复杂的目录上,它比递归获取文件大小快 1000 倍以上。太棒了!【参考方案7】:

你应该使用这个代码:

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;

【讨论】:

对我来说很好的解决方案,我有一个包含一些音频文件的文件夹,它对我来说非常适合! (我在这个文件夹中没有子文件夹!)【参考方案8】:

这是一些避免递归的代码,并且还计算了物理大小而不是逻辑大小:

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;

【讨论】:

这是计算文件/文件夹大小的绝对正确答案 我很惊讶地看到(在 Android 上)每个文件夹占用大约 4KB,即使它是空的。想知道他们为什么这样做。 @androiddeveloper 这是扇区大小。您会注意到在任何桌面操作系统上都是如此。 @AndroidDev 好的。谢谢 该值与三星我的文件应用程序报告的文件夹中选定文件的详细信息相匹配【参考方案9】:

您可以查询 MediaStore 以获取内部存储上的目录大小。这比获取目录中每个文件的长度的递归方法快得多。您必须授予READ_EXTERNAL_STORAGE 权限。

示例:

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

用法:

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

输出:

/storage/emulated/0/DCIM 30.86 MB

【讨论】:

是的,如果谈论媒体文件,这是最好的解决方案 "/%/%" - 错误,如果您不想排除根文件夹中的文件,则应该是 /% - getFolderSize(context, folderRoot);,使用您的解决方案 "/%/%" 它只会得到大小该根文件夹中的子文件夹【参考方案10】:

希望对你有帮助

导入这个

import android.text.format.Formatter;

文件大小

public static String fileSize(File file, Context context) 
        return Formatter.formatFileSize(context, file.length());
    

文件夹大小

 public static String forlderSize(File file, Context context) 
        long length = 0;
        File[] folderFiles = file.listFiles();
        for (File f : folderFiles) 
            length += f.length();
        

        return Formatter.formatFileSize(context, length);
    

【讨论】:

【参考方案11】:

这是 Linh Toòng 的回答中的一个 sn-p,还有一些检查(主要是为了阻止 Android Studio 的警告!)

private long getFolderSize(File file) 

        if (file == null || !file.exists())
            return 0;

        long size = 0;

        if (file.isDirectory()) 

            File[] files = file.listFiles();

            if (files == null || files.length == 0)
                return size;

            for (File f : files)
                size += getFolderSize(f);

         else
            size += file.length();

        return size;

    

【讨论】:

以上是关于如何在 Android 中获取 SD 卡上文件夹的大小?的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Android API 24+ 在 SD 卡上写入文件

在 Android 应用程序中解压缩 sd 卡上的压缩文件

构建 AOSP:如何在 SD 卡上包含文件?

Android Dev:从存储在 SD 卡上的临时文件创建位图,设置 ImageView,然后将其存储在本地

检查android sd卡上是不是存在目录

删除 SD 卡上的文件夹