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

时间:2020-11-27 09:00:58

Is it possible to easily get the size of a folder on the SD card? I use a folder for caching of images, and would like to present the total size of all cached images. Is there a way to this other than iterating over each file? They all reside inside the same folder?

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

9 个解决方案

#1


38  

Just go through all files and sum the length of them:

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

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

NOTE: Function written by hand so it could not compile!

注意:手写的功能无法编译!

EDITED: recursive call fixed.

编辑:递归调用修复。

EDITED: dirList.length changed to fileList.length.

已编辑:dirList.length已更改为fileList.length。

#2


14  

Here's some code that avoids recursion, and also calculates the physical size instead of the logical size:

这里有一些代码可以避免递归,还可以计算物理大小而不是逻辑大小:

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

#3


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

#4


5  

you should use this code:

你应该使用这段代码:

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

#5


3  

The way of #Moss is right. This is my code for those who want to change bytes to human readable format. You just need to assign path of your folder to dirSize(String path) and get human readable format based on byte, kilo, mega and etc.

#Moss的方式是正确的。对于那些想要将字节更改为人类可读格式的人来说,这是我的代码。您只需要将文件夹的路径分配给dirSize(String path),并根据byte,kilo,mega等获取人类可读的格式。

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


2  

Problem with other solution is that they provide you only logical size of all files in specified directory. It will be different from actual (physical) used space. If your directory has a lot of subdirectories and/or small files, there may be a huge difference between logical and actual size of directory.

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

Here is what I found how to take in count physical structure of FS.

以下是我发现如何计算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;
    }
}

You can use StatFs to get block size:

您可以使用StatF来获取块大小:

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

#7


1  

below method return you size of folder:-

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

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

call above method :-

以上方法致电: -

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

long folder_size=getFolderSize(file);

return you size of folder.

返回文件夹的大小。

#8


0  

Iterating through all files is less than 5 lines of code and the only reasonable way to do this. If you want to get ugly you could also run a system command (Runtime.getRuntime().exec("du");) and catch the output ;)

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

#9


0  

You can query MediaStore for a directory size on internal storage. This is much faster than a recursive method getting the length of each file in a directory. You must have READ_EXTERNAL_STORAGE permission granted.

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

Example:

/**
 * 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/emulated/0/DCIM 30.86 MB

/ storage / emulated / 0 / DCIM 30.86 MB

#1


38  

Just go through all files and sum the length of them:

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

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

NOTE: Function written by hand so it could not compile!

注意:手写的功能无法编译!

EDITED: recursive call fixed.

编辑:递归调用修复。

EDITED: dirList.length changed to fileList.length.

已编辑:dirList.length已更改为fileList.length。

#2


14  

Here's some code that avoids recursion, and also calculates the physical size instead of the logical size:

这里有一些代码可以避免递归,还可以计算物理大小而不是逻辑大小:

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

#3


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

#4


5  

you should use this code:

你应该使用这段代码:

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

#5


3  

The way of #Moss is right. This is my code for those who want to change bytes to human readable format. You just need to assign path of your folder to dirSize(String path) and get human readable format based on byte, kilo, mega and etc.

#Moss的方式是正确的。对于那些想要将字节更改为人类可读格式的人来说,这是我的代码。您只需要将文件夹的路径分配给dirSize(String path),并根据byte,kilo,mega等获取人类可读的格式。

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


2  

Problem with other solution is that they provide you only logical size of all files in specified directory. It will be different from actual (physical) used space. If your directory has a lot of subdirectories and/or small files, there may be a huge difference between logical and actual size of directory.

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

Here is what I found how to take in count physical structure of FS.

以下是我发现如何计算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;
    }
}

You can use StatFs to get block size:

您可以使用StatF来获取块大小:

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

#7


1  

below method return you size of folder:-

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

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

call above method :-

以上方法致电: -

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

long folder_size=getFolderSize(file);

return you size of folder.

返回文件夹的大小。

#8


0  

Iterating through all files is less than 5 lines of code and the only reasonable way to do this. If you want to get ugly you could also run a system command (Runtime.getRuntime().exec("du");) and catch the output ;)

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

#9


0  

You can query MediaStore for a directory size on internal storage. This is much faster than a recursive method getting the length of each file in a directory. You must have READ_EXTERNAL_STORAGE permission granted.

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

Example:

/**
 * 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/emulated/0/DCIM 30.86 MB

/ storage / emulated / 0 / DCIM 30.86 MB