Android获得内部/外部存储器的自由大小


98

我想以编程方式获取设备内部/外部存储上的可用内存大小。我正在使用这段代码:

StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
long bytesAvailable = (long)stat.getBlockSize() *(long)stat.getBlockCount();
long megAvailable = bytesAvailable / 1048576;
Log.e("","Available MB : "+megAvailable);

File path = Environment.getDataDirectory();
StatFs stat2 = new StatFs(path.getPath());
long blockSize = stat2.getBlockSize();
long availableBlocks = stat2.getAvailableBlocks();
String format =  Formatter.formatFileSize(this, availableBlocks * blockSize);
Log.e("","Format : "+format);

我得到的结果是:

11-15 10:27:18.844: E/(25822): Available MB : 7572
11-15 10:27:18.844: E/(25822): Format : 869MB

问题是我想获得1,96GB现在的SdCard的可用内存。如何修复此代码,以便获得免费的尺寸?


从API级别18开始,他们将方法重命名为Long。可能您需要在此之前添加API级别的检查
Jayshil Dave 2015年

所有解决方案我都尝试过不工作,当我将其格式化为内部存储设备时...请问我,如何实现这一目标?
Yogesh Rathi

Answers:


182

以下是您所需的代码:

public static boolean externalMemoryAvailable() {
        return android.os.Environment.getExternalStorageState().equals(
                android.os.Environment.MEDIA_MOUNTED);
    }

    public static String getAvailableInternalMemorySize() {
        File path = Environment.getDataDirectory();
        StatFs stat = new StatFs(path.getPath());
        long blockSize = stat.getBlockSizeLong();
        long availableBlocks = stat.getAvailableBlocksLong();
        return formatSize(availableBlocks * blockSize);
    }

    public static String getTotalInternalMemorySize() {
        File path = Environment.getDataDirectory();
        StatFs stat = new StatFs(path.getPath());
        long blockSize = stat.getBlockSizeLong();
        long totalBlocks = stat.getBlockCountLong();
        return formatSize(totalBlocks * blockSize);
    }

    public static String getAvailableExternalMemorySize() {
        if (externalMemoryAvailable()) {
            File path = Environment.getExternalStorageDirectory();
            StatFs stat = new StatFs(path.getPath());
            long blockSize = stat.getBlockSizeLong();
            long availableBlocks = stat.getAvailableBlocksLong();
            return formatSize(availableBlocks * blockSize);
        } else {
            return ERROR;
        }
    }

    public static String getTotalExternalMemorySize() {
        if (externalMemoryAvailable()) {
            File path = Environment.getExternalStorageDirectory();
            StatFs stat = new StatFs(path.getPath());
            long blockSize = stat.getBlockSizeLong();
            long totalBlocks = stat.getBlockCountLong();
            return formatSize(totalBlocks * blockSize);
        } else {
            return ERROR;
        }
    }

    public static String formatSize(long size) {
        String suffix = null;

        if (size >= 1024) {
            suffix = "KB";
            size /= 1024;
            if (size >= 1024) {
                suffix = "MB";
                size /= 1024;
            }
        }

        StringBuilder resultBuffer = new StringBuilder(Long.toString(size));

        int commaOffset = resultBuffer.length() - 3;
        while (commaOffset > 0) {
            resultBuffer.insert(commaOffset, ',');
            commaOffset -= 3;
        }

        if (suffix != null) resultBuffer.append(suffix);
        return resultBuffer.toString();
    }

获取RAM大小

ActivityManager actManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
MemoryInfo memInfo = new ActivityManager.MemoryInfo();
actManager.getMemoryInfo(memInfo);
long totalMemory = memInfo.totalMem;

2
getBlockSize()getBlockCount已弃用。
Nima G

2
@DineshPrajapati感谢您的回答,我有一个查询,如果我使用Environment.getRootDirectory()而不是Environment.getDataDirectory来计算内部存储,我会得到一些输出..这是指内部内存其他内存..
AK Joshi

3
@DineshPrajapati ..在MOTO G2上测试获得错误的外部存储数据
AK Joshi

1
最后使用Long作为较新的API级别(> 18)
Gun2sh 2015年

1
非常感谢您分享知识
Kishan Soni 2015年

40

这是我做到的方式:

StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
long bytesAvailable;
if (android.os.Build.VERSION.SDK_INT >= 
    android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
    bytesAvailable = stat.getBlockSizeLong() * stat.getAvailableBlocksLong();
}
else {
    bytesAvailable = (long)stat.getBlockSize() * (long)stat.getAvailableBlocks();
}
long megAvailable = bytesAvailable / (1024 * 1024);
Log.e("","Available MB : "+megAvailable);

2
但这是不受欢迎的:(
abbasalim

@ ArMo372,你们是否找到了替换代码?
SimpleCoder

3
只需将getBlockSizeand 替换getAvailableBlocksgetBlockSizeLongand即可getAvailableBlocksLong
smg

1
这没有获得正确的可用空间。这将得到1141而不是1678 @smg

1
当我将其格式化为内部存储时,解决方案不起作用...您能取悦我,如何实现这一目标
Yogesh Rathi,

27

从API 9开始,您可以执行以下操作:

long freeBytesInternal = new File(ctx.getFilesDir().getAbsoluteFile().toString()).getFreeSpace();
long freeBytesExternal = new File(getExternalFilesDir(null).toString()).getFreeSpace();

2
File.getUsableSpace()可能更好,因为您可能不是以root身份运行。
2014年

File.getUsableSpace()看起来像一个更简单的方法来使用,而不是使用StatFs。我为什么要使用StatFs@MarkCarter?
StuStirling,2014年

1
@ DiscoS2如果您的minSdkVersion小于9,则应使用StatF。– 2014
标记

1
您还将如何监视存储更改?
Android开发人员

24

要获取所有可用的存储文件夹(包括SD卡),请首先获取存储文件:

File internalStorageFile=getFilesDir();
File[] externalStorageFiles=ContextCompat.getExternalFilesDirs(this,null);

然后,您可以获取每一个的可用大小。

有3种方法可以做到:

API 8及以下:

StatFs stat=new StatFs(file.getPath());
long availableSizeInBytes=stat.getBlockSize()*stat.getAvailableBlocks();

API 9及以上:

long availableSizeInBytes=file.getFreeSpace();

API 18及更高版本(如果可以使用以前的版本,则不需要):

long availableSizeInBytes=new StatFs(file.getPath()).getAvailableBytes(); 

要获得现在得到的格式良好的字符串,可以使用:

String formattedResult=android.text.format.Formatter.formatShortFileSize(this,availableSizeInBytes);

或者,如果您希望看到确切的字节数,也可以使用它,但很好:

NumberFormat.getInstance().format(availableSizeInBytes);

请注意,我认为内部存储可能与第一个外部存储相同,因为第一个是模拟的。


编辑:在Android Q及更高版本上使用StorageVolume,我认为可以使用以下方法获取每个对象的可用空间:

    val storageManager = getSystemService(Context.STORAGE_SERVICE) as StorageManager
    val storageVolumes = storageManager.storageVolumes
    AsyncTask.execute {
        for (storageVolume in storageVolumes) {
            val uuid: UUID = storageVolume.uuid?.let { UUID.fromString(it) } ?: StorageManager.UUID_DEFAULT
            val allocatableBytes = storageManager.getAllocatableBytes(uuid)
            Log.d("AppLog", "allocatableBytes:${android.text.format.Formatter.formatShortFileSize(this,allocatableBytes)}")
        }
    }

我不确定这是否正确,而且我找不到找到每个组件的总大小的方法,所以我在这里写了一下,并在这里问了一下


1
如何在使用API​​ 23的设备上的可移动SD卡(或USB OTG闪存驱动器)上获得可用空间?无论Nexus 5(棉花糖6.0.1)上的实际存储大小如何,新的StatFs(file.getPath())。getAvailableBytes()或file.getUsableSpace()都会提供972546048字节。
isabsent

@isabsent Nexus 5没有SD卡插槽。你怎么检查的?
Android开发人员

我已经使用USB OTG闪存驱动器对其进行了检查。
isabsent's

@isabsent我从没用过。抱歉。它在API 22及以下版本上是否运作良好?
Android开发人员

1
@Smeet是否可以在Android 6或更高版本上尝试?如果是这样,可能是这样的问题:code.google.com/p/android/issues/detail?id=200326
android开发人员

9

@ Android-Droid-您错误地Environment.getExternalStorageDirectory()指向了外部存储,该存储不必是SD卡,它也可以装入内部存储器。看到:

查找外部SD卡位置


7

试试这个简单的代码片段

    public static String readableFileSize() {
    long availableSpace = -1L;
    StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2)
        availableSpace = (long) stat.getBlockSizeLong() * (long) stat.getAvailableBlocksLong();
    else
        availableSpace = (long) stat.getAvailableBlocks() * (long) stat.getBlockSize();

    if(availableSpace <= 0) return "0";
    final String[] units = new String[] { "B", "kB", "MB", "GB", "TB" };
    int digitGroups = (int) (Math.log10(availableSpace)/Math.log10(1024));
    return new DecimalFormat("#,##0.#").format(availableSpace/Math.pow(1024, digitGroups)) + " " + units[digitGroups];
}

谢谢,但我有java.lang.ArrayIndexOutOfBoundsException: length=5; index=-2147483648错误,似乎digitGroups结果是-2147483648。
Acuna

当我将其格式化为内部存储时,解决方案不起作用...您能取悦我,如何实现这一目标
Yogesh Rathi,

6

如果您获得内部和外部存储路径,则很容易找到可用的存储。另外手机的外部存储路径真的很容易找到使用

Environment.getExternalStorageDirectory()。getPath();

因此,我只是专注于如何找出外部可移动存储的路径,例如可移动sdcard,USB OTG(未测试USB OTG,因为我没有USB OTG)。

下面的方法将列出所有可能的外部可移动存储路径。

 /**
     * This method returns the list of removable storage and sdcard paths.
     * I have no USB OTG so can not test it. Is anybody can test it, please let me know
     * if working or not. Assume 0th index will be removable sdcard path if size is
     * greater than 0.
     * @return the list of removable storage paths.
     */
    public static HashSet<String> getExternalPaths()
    {
    final HashSet<String> out = new HashSet<String>();
    String reg = "(?i).*vold.*(vfat|ntfs|exfat|fat32|ext3|ext4).*rw.*";
    String s = "";
    try
    {
        final Process process = new ProcessBuilder().command("mount").redirectErrorStream(true).start();
        process.waitFor();
        final InputStream is = process.getInputStream();
        final byte[] buffer = new byte[1024];
        while (is.read(buffer) != -1)
        {
            s = s + new String(buffer);
        }
        is.close();
    }
    catch (final Exception e)
    {
        e.printStackTrace();
    }

    // parse output
    final String[] lines = s.split("\n");
    for (String line : lines)
    {
        if (!line.toLowerCase(Locale.US).contains("asec"))
        {
            if (line.matches(reg))
            {
                String[] parts = line.split(" ");
                for (String part : parts)
                {
                    if (part.startsWith("/"))
                    {
                        if (!part.toLowerCase(Locale.US).contains("vold"))
                        {
                            out.add(part.replace("/media_rw","").replace("mnt", "storage"));
                        }
                    }
                }
            }
        }
    }
    //Phone's external storage path (Not removal SDCard path)
    String phoneExternalPath = Environment.getExternalStorageDirectory().getPath();

    //Remove it if already exist to filter all the paths of external removable storage devices
    //like removable sdcard, USB OTG etc..
    //When I tested it in ICE Tab(4.4.2), Swipe Tab(4.0.1) with removable sdcard, this method includes
    //phone's external storage path, but when i test it in Moto X Play (6.0) with removable sdcard,
    //this method does not include phone's external storage path. So I am going to remvoe the phone's
    //external storage path to make behavior consistent in all the phone. Ans we already know and it easy
    // to find out the phone's external storage path.
    out.remove(phoneExternalPath);

    return out;
}

我记得,在某些设备上使用常量名称进行路径处理可能无法正常工作,因为某些设备可能具有自己的路径。我希望不是这样。+1的努力。
Android开发者

1
@androiddeveloper谢谢亲爱的投票。我需要所有人的支持才能在您的设备中测试此代码,因为我没有所有设备,但是已经在4种不同的设备中进行了测试,并且工作正常。请评论这里不适用于任何人的手机。
Smeet

当我将其格式化为内部存储时,解决方案不起作用...您能取悦我,如何实现这一目标
Yogesh Rathi,

4

快速添加到外部存储器主题

请不要externalMemoryAvailable()对Dinesh Prajapati的答案中的方法名称感到困惑。

Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())如果存在介质并通过读取/写入访问权限将其安装在其安装点,则可为您提供内存的当前状态。您true甚至可以在没有SD卡的设备上使用Nexus 5等设备,但是在进行任何存储操作之前,这仍然是“必备”方法。

要检查设备上是否有SD卡,可以使用方法 ContextCompat.getExternalFilesDirs()

它没有显示瞬态设备,例如USB闪存驱动器。

另请注意,ContextCompat.getExternalFilesDirs()在Android 4.3及更低版本上,始终仅返回1个条目(如果有SD卡,则返回SD卡,否则返回Internal)。您可以在此处了解更多信息。

  public static boolean isSdCardOnDevice(Context context) {
    File[] storages = ContextCompat.getExternalFilesDirs(context, null);
    if (storages.length > 1 && storages[0] != null && storages[1] != null)
        return true;
    else
        return false;
}

就我而言,这已经足够了,但是请不要忘记某些Android设备可能具有2张SD卡,因此,如果需要所有这些,请调整上面的代码。


2
@RequiresApi(api = Build.VERSION_CODES.O)
private void showStorageVolumes() {
    StorageStatsManager storageStatsManager = (StorageStatsManager) getSystemService(Context.STORAGE_STATS_SERVICE);
    StorageManager storageManager = (StorageManager) getSystemService(Context.STORAGE_SERVICE);
    if (storageManager == null || storageStatsManager == null) {
        return;
    }
    List<StorageVolume> storageVolumes = storageManager.getStorageVolumes();
    for (StorageVolume storageVolume : storageVolumes) {
        final String uuidStr = storageVolume.getUuid();
        final UUID uuid = uuidStr == null ? StorageManager.UUID_DEFAULT : UUID.fromString(uuidStr);
        try {
            Log.d("AppLog", "storage:" + uuid + " : " + storageVolume.getDescription(this) + " : " + storageVolume.getState());
            Log.d("AppLog", "getFreeBytes:" + Formatter.formatShortFileSize(this, storageStatsManager.getFreeBytes(uuid)));
            Log.d("AppLog", "getTotalBytes:" + Formatter.formatShortFileSize(this, storageStatsManager.getTotalBytes(uuid)));
        } catch (Exception e) {
            // IGNORED
        }
    }
}

StorageStatsManager类引入了Android O及更高版本,可以为您提供外部/内部存储中的可用字节和总字节。有关源代码的详细信息,您可以阅读我的以下文章。您可以使用反射低于Android O

https://medium.com/cashify-engineering/how-to-get-storage-stats-in-android-o-api-26-4b92eca6805b


2

这是我做到的方式

内部总内存

double totalSize = new File(getApplicationContext().getFilesDir().getAbsoluteFile().toString()).getTotalSpace();
double totMb = totalSize / (1024 * 1024);

内部自由尺寸

 double availableSize = new File(getApplicationContext().getFilesDir().getAbsoluteFile().toString()).getFreeSpace();
    double freeMb = availableSize/ (1024 * 1024);

外部可用和总内存

 long freeBytesExternal =  new File(getExternalFilesDir(null).toString()).getFreeSpace();
       int free = (int) (freeBytesExternal/ (1024 * 1024));
        long totalSize =  new File(getExternalFilesDir(null).toString()).getTotalSpace();
        int total= (int) (totalSize/ (1024 * 1024));
       String availableMb = free+"Mb out of "+total+"MB";

0

关于外部记忆,还有另一种方法:
File external = Environment.getExternalStorageDirectory(); free:external.getFreeSpace(); total:external.getTotalSpace();


0

在检查了不同的解决方案之后,我自己编写了代码,这是查找的完整代码

  • 外部记忆体总数
  • 可用的外部存储器
  • 使用的外部存储器
  • 内置内存
  • 使用的内部存储器
  • 可用内部内存

''''

object DeviceMemoryUtil {
private const val error: String = "Something went wrog"
private const val noExternalMemoryDetected = "No external Storage detected"
private var totalExternalMemory: Long = 0
private var freeExternalMemory: Long = 0
private var totalInternalStorage: Long = 0
private var freeInternalStorage: Long = 0

/**
 * Checks weather external memory is available or not
 */
private fun externalMemoryAvailable(): Boolean {
    return Environment.getExternalStorageState() ==
            Environment.MEDIA_MOUNTED
}

/**
 *Gives total external memory
 * @return String Size of external memory
 * @return Boolean True if memory size is returned
 */
fun getTotalExternalMemorySize(): Pair<String?, Boolean> {
    val dirs: Array<File> = ContextCompat.getExternalFilesDirs(CanonApplication.getCanonAppInstance(), null)
    return if (externalMemoryAvailable()) {
        if (dirs.size > 1) {
            val stat = StatFs(dirs[1].path)
            val blockSize = stat.blockSizeLong
            val totalBlocks = stat.blockCountLong
            var totalExternalSize = totalBlocks * blockSize
            totalExternalMemory = totalExternalSize
            Pair(formatSize(totalExternalSize), true)
        } else {
            Pair(error, false)
        }
    } else {
        Pair(noExternalMemoryDetected, false)
    }
}

/**
 * Gives free external memory size
 * @return String Size of free external memory
 * @return Boolean True if memory size is returned
 */
fun getAvailableExternalMemorySize(): Pair<String?, Boolean> {
    val dirs: Array<File> = ContextCompat.getExternalFilesDirs(CanonApplication.getCanonAppInstance(), null)
    if (externalMemoryAvailable()) {
        return if (dirs.size > 1) {
            val stat = StatFs(dirs[1].path)
            val blockSize = stat.blockSizeLong
            val availableBlocks = stat.availableBlocksLong
            var freeExternalSize = blockSize * availableBlocks
            freeExternalMemory = freeExternalSize
            Pair(formatSize(freeExternalSize), true)
        } else {
            Pair(error, false)
        }
    } else {
        return Pair(noExternalMemoryDetected, false)
    }
}

/**
 * Gives used external memory size
 *  @return String Size of used external memory
 * @return Boolean True if memory size is returned
 */
fun getUsedExternalMemorySize(): Pair<String?, Boolean> {
    return if (externalMemoryAvailable()) {
        val totalExternalSize = getTotalExternalMemorySize()
        val freeExternalSize = getAvailableExternalMemorySize()
        if (totalExternalSize.second && freeExternalSize.second) {
            var usedExternalVolume = totalExternalMemory - freeExternalMemory
            Pair(formatSize(usedExternalVolume), true)
        } else {
            Pair(error, false)
        }
    } else {
        Pair(noExternalMemoryDetected, false)
    }
}

/**
 *Formats the long to size of memory in gb,mb etc.
 * @param size Size of memory
 */
fun formatSize(size: Long): String? {
    return android.text.format.Formatter.formatFileSize(CanonApplication.getCanonAppInstance(), size)
}

/**
 * Gives total internal memory size
 *  @return String Size of total internal memory
 * @return Boolean True if memory size is returned
 */
fun getTotalInternalStorage(): Pair<String?, Boolean> {
    if (showStorageVolumes()) {
        return Pair(formatSize(totalInternalStorage), true)
    } else {
        return Pair(error, false)
    }

}

/**
 * Gives free or available internal memory size
 *  @return String Size of free internal memory
 * @return Boolean True if memory size is returned
 */
fun getFreeInternalStorageVolume(): Pair<String?, Boolean> {
    return if (showStorageVolumes()) {
        Pair(formatSize(freeInternalStorage), true)
    } else {
        Pair(error, false)
    }
}

/**
 *For calculation of internal storage
 */
private fun showStorageVolumes(): Boolean {
    val storageManager = CanonApplication.canonApplicationInstance.applicationContext.getSystemService(Context.STORAGE_SERVICE) as StorageManager
    val storageStatsManager = CanonApplication.canonApplicationInstance.applicationContext.getSystemService(Context.STORAGE_STATS_SERVICE) as StorageStatsManager
    if (storageManager == null || storageStatsManager == null) {
        return false
    }
    val storageVolumes: List<StorageVolume> = storageManager.storageVolumes
    for (storageVolume in storageVolumes) {
        var uuidStr: String? = null
        storageVolume.uuid?.let {
            uuidStr = it
        }
        val uuid: UUID = if (uuidStr == null) StorageManager.UUID_DEFAULT else UUID.fromString(uuidStr)
        return try {
            freeInternalStorage = storageStatsManager.getFreeBytes(uuid)
            totalInternalStorage = storageStatsManager.getTotalBytes(uuid)
            true
        } catch (e: Exception) {
            // IGNORED
            false
        }
    }
    return false
}

fun getTotalInternalExternalMemory(): Pair<Long?, Boolean> {
    if (externalMemoryAvailable()) {
        if (getTotalExternalMemorySize().second) {
            if (getTotalInternalStorage().second) {
                return Pair(totalExternalMemory + totalInternalStorage, true)
            } else {
                return Pair(0, false)
            }
        }
        return Pair(0, false)
    } else {
        if (getTotalInternalStorage().second) {
            return Pair(totalInternalStorage, true)
        } else {
            return Pair(0, false)
        }
    }

}

fun getTotalFreeStorage(): Pair<Long,Boolean> {
    if (externalMemoryAvailable()){
        if(getFreeInternalStorageVolume().second){
            getFreeInternalStorageVolume()
            getAvailableExternalMemorySize()
                return Pair(freeExternalMemory + freeInternalStorage,true)
        }
        else{
            return Pair(0,false)
        }
    }
    else {
        if (getFreeInternalStorageVolume().second){
            getFreeInternalStorageVolume()
            return Pair(freeInternalStorage,true)
        }
      else{
            return Pair(0,false)
        }
    }

}}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.