如何检查安卓设备上的可用空间?在 SD 卡上?[复制]

IT小君   2021-10-07T23:00:26

如何查看 Android 设备上还剩多少 MB 或 GB?我正在使用 JAVA 和 android SDK 2.0.1。

是否有任何系统服务会公开这样的内容?

评论(9)
IT小君

Yaroslav 的回答将给出 SD 卡的大小,而不是可用空间。StatFsgetAvailableBlocks()将返回正常程序仍可访问的块数。这是我正在使用的功能:

public static float megabytesAvailable(File f) {
    StatFs stat = new StatFs(f.getPath());
    long bytesAvailable = (long)stat.getBlockSize() * (long)stat.getAvailableBlocks();
    return bytesAvailable / (1024.f * 1024.f);
}

上面的代码参考了一些截至 2014 年 8 月 13 日已弃用的函数。我在下面复制了一个更新版本:

public static float megabytesAvailable(File f) {
    StatFs stat = new StatFs(f.getPath());
    long bytesAvailable = 0;
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2)
        bytesAvailable = (long) stat.getBlockSizeLong() * (long) stat.getAvailableBlocksLong();
    else
        bytesAvailable = (long) stat.getBlockSize() * (long) stat.getAvailableBlocks();
    return bytesAvailable / (1024.f * 1024.f);
}
2021-10-07T23:00:26   回复
IT小君

试试这个代码

StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());

long bytesAvailable = (long)stat.getBlockSize() *(long)stat.getBlockCount();
long megAvailable   = bytesAvailable / 1048576;

System.out.println("Megs: " + megAvailable);

更新:

getBlockCount() - 返回SD卡的大小;

getAvailableBlocks() - 返回正常程序仍可访问的块数(感谢 Joe)

2021-10-07T23:00:26   回复
IT小君

我设计了一些随时可用的函数来获得不同单位的可用空间。您可以通过简单地将其中任何一种方法复制到您的项目中来使用这些方法。

/**
 * @return Number of bytes available on External storage
 */
public static long getAvailableSpaceInBytes() {
    long availableSpace = -1L;
    StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
    availableSpace = (long) stat.getAvailableBlocks() * (long) stat.getBlockSize();

    return availableSpace;
}


/**
 * @return Number of kilo bytes available on External storage
 */
public static long getAvailableSpaceInKB(){
    final long SIZE_KB = 1024L;
    long availableSpace = -1L;
    StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
    availableSpace = (long) stat.getAvailableBlocks() * (long) stat.getBlockSize();
    return availableSpace/SIZE_KB;
}
/**
 * @return Number of Mega bytes available on External storage
 */
public static long getAvailableSpaceInMB(){
    final long SIZE_KB = 1024L;
    final long SIZE_MB = SIZE_KB * SIZE_KB;
    long availableSpace = -1L;
    StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
    availableSpace = (long) stat.getAvailableBlocks() * (long) stat.getBlockSize();
    return availableSpace/SIZE_MB;
}

/**
 * @return Number of gega bytes available on External storage
 */
public static long getAvailableSpaceInGB(){
    final long SIZE_KB = 1024L;
    final long SIZE_GB = SIZE_KB * SIZE_KB * SIZE_KB;
    long availableSpace = -1L;
    StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
    availableSpace = (long) stat.getAvailableBlocks() * (long) stat.getBlockSize();
    return availableSpace/SIZE_GB;
}
2021-10-07T23:00:27   回复
IT小君

基于答案,添加了对 Android 版本 < 18 的支持

public static float megabytesAvailable(File file) {
    StatFs stat = new StatFs(file.getPath());
    long bytesAvailable;
    if(Build.VERSION.SDK_INT >= 18){
        bytesAvailable = getAvailableBytes(stat);
    }
    else{
        //noinspection deprecation
        bytesAvailable = stat.getBlockSize() * stat.getAvailableBlocks();
    }

    return bytesAvailable / (1024.f * 1024.f);
}

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
private static long getAvailableBytes(StatFs stat) {
    return stat.getBlockSizeLong() * stat.getAvailableBlocksLong();
}
2021-10-07T23:00:27   回复
IT小君

自 API 版本 18 以来引入了新方法。

我使用类似的东西来估计大磁盘缓存大小(用于 Picasso OkHttp 下载器缓存)。辅助方法是这样的:

private static final String BIG_CACHE_PATH = "my-cache-dir";
private static final float  MAX_AVAILABLE_SPACE_USE_FRACTION = 0.9f;
private static final float  MAX_TOTAL_SPACE_USE_FRACTION     = 0.25f;

static File createDefaultCacheDirExample(Context context) {
    File cache = new File(context.getApplicationContext().getCacheDir(), BIG_CACHE_PATH);
    if (!cache.exists()) {
        cache.mkdirs();
    }
    return cache;
}

/**
 * Calculates minimum of available or total fraction of disk space
 * 
 * @param dir
 * @return space in bytes
 */
@SuppressLint("NewApi")
static long calculateAvailableCacheSize(File dir) {
    long size = 0;
    try {
        StatFs statFs = new StatFs(dir.getAbsolutePath());
        int sdkInt = Build.VERSION.SDK_INT;
        long totalBytes;
        long availableBytes;
        if (sdkInt < Build.VERSION_CODES.JELLY_BEAN_MR2) {
            int blockSize = statFs.getBlockSize();
            availableBytes = ((long) statFs.getAvailableBlocks()) * blockSize;
            totalBytes = ((long) statFs.getBlockCount()) * blockSize;
        } else {
            availableBytes = statFs.getAvailableBytes();
            totalBytes = statFs.getTotalBytes();
        }
        // Target at least 90% of available or 25% of total space
        size = (long) Math.min(availableBytes * MAX_AVAILABLE_SPACE_USE_FRACTION, totalBytes * MAX_TOTAL_SPACE_USE_FRACTION);
    } catch (IllegalArgumentException ignored) {
        // ignored
    }
    return size;
}
2021-10-07T23:00:27   回复
IT小君

另外,如果您想检查内部存储器上的可用空间,请使用:

File path = Environment.getDataDirectory();
StatFs stat = new StatFs(path.getPath());

...

2021-10-07T23:00:27   回复
IT小君

Google 在入门页面上提供了相关信息- 请参阅查询可用空间。他们说你可以检查可用空间,getFreeSpace()但他们说这是不准确的,你应该期望比这少一点的可用空间。他们说:

如果返回的数字比您要保存的数据大小多几 MB,或者文件系统未满 90%,那么继续操作可能是安全的。否则,您可能不应该写入存储。

他们还提出建议,通常更有用的是根本不检查可用空间,而只是检查try catch错误:

在保存文件之前,您无需检查可用空间量。您可以尝试立即写入文件,然后在发生 IOException 时捕获该异常。如果您不确切知道需要多少空间,则可能需要这样做。例如,如果您在通过将 PNG 图像转换为 JPEG 来保存文件之前更改了文件的编码,则您事先不会知道文件的大小。

我建议仅对于非常大的文件大小,您应该事先检查可用存储空间,以免浪费时间下载或创建明显太大而无法容纳的文件。在任何一种情况下,您都应该始终使用,try catch所以我认为事先检查可用空间的唯一理由是不必要地使用资源和时间太多。

2021-10-07T23:00:27   回复
IT小君

我希望这段代码可以帮助其他人。经测试工作正常。感谢上述成员澄清它。

/**
 * Get the free disk available space in boolean to download requested file 
 * 
 * @return boolean value according to size availability
 */

protected static boolean isMemorySizeAvailableAndroid(long download_bytes, boolean isExternalMemory) {
    boolean isMemoryAvailable = false;
    long freeSpace = 0;

    // if isExternalMemory get true to calculate external SD card available size
    if(isExternalMemory){
        try {
            StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
            freeSpace = (long) stat.getAvailableBlocks() * (long) stat.getBlockSize();
            if(freeSpace > download_bytes){
                isMemoryAvailable = true;
            }else{
                isMemoryAvailable = false;
            }
        } catch (Exception e) {e.printStackTrace(); isMemoryAvailable = false;}
    }else{
        // find phone available size
        try {
            StatFs stat = new StatFs(Environment.getDataDirectory().getPath());
            freeSpace = (long) stat.getAvailableBlocks() * (long) stat.getBlockSize();
            if(freeSpace > download_bytes){
                isMemoryAvailable = true;
            }else{
                isMemoryAvailable = false;
            }
        } catch (Exception e) {e.printStackTrace(); isMemoryAvailable = false;}
    }

    return isMemoryAvailable;
}
2021-10-07T23:00:28   回复
IT小君
public String TotalExtMemory()
{
    StatFs statFs = new StatFs(Environment.getExternalStorageDirectory().getAbsolutePath());   
    int Total = (statFs.getBlockCount() * statFs.getBlockSize()) / 1048576;

    String strI = Integer.toString(Total);
    return strI;
}

public String FreeExtMemory()
{
    StatFs statFs = new StatFs(Environment.getExternalStorageDirectory().getAbsolutePath());
    int Free  = (statFs.getAvailableBlocks() * statFs.getBlockSize()) / 1048576;
    String strI = Integer.toString(Free);
    return strI;
}

public String BusyExtMemory()
{
    StatFs statFs = new StatFs(Environment.getExternalStorageDirectory().getAbsolutePath());   
    int Total = (statFs.getBlockCount() * statFs.getBlockSize()) / 1048576;
    int Free  = (statFs.getAvailableBlocks() * statFs.getBlockSize()) / 1048576;
    int Busy  = Total - Free;
    String strI = Integer.toString(Busy);
    return strI;
}
2021-10-07T23:00:28   回复