Android分区/共享存储下如何通过ACTION_CREATE_DOCUMENT返回的URI查询可用空间
针对SAF返回Content URI的存储空间查询方案
标准适配方案(适配Android 7.0/API 24及以上版本)
目前绝大多数活跃Android设备都运行Android 7.0及以上系统,官方提供了直接适配SAF返回Uri的查询API,不需要访问文件系统,也不需要申请额外权限。
实现逻辑是通过DocumentsContract工具类从目标Uri解析出对应的存储卷,再直接查询存储卷的可用空间,代码示例如下:
import android.os.Build; import android.os.storage.StorageManager; import android.os.storage.StorageVolume; import android.provider.DocumentsContract; import android.net.Uri; /** * 校验目标Uri对应存储位置是否有足够空间 * @param targetUri ACTION_CREATE_DOCUMENT返回的content Uri * @param requiredSize 待写入文件的总大小,单位为字节 * @return 空间足够返回true,否则返回false */ public boolean hasEnoughStorage(Uri targetUri, long requiredSize) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { // 7.0以下设备占比不足1%,可根据业务需求选择跳过校验或走降级逻辑 return true; } try { StorageManager storageManager = getSystemService(StorageManager.class); DocumentsContract.Path docPath = DocumentsContract.findDocumentPath(getContentResolver(), targetUri); if (docPath == null) { return false; } StorageVolume targetVolume = docPath.getStorageVolume(); if (targetVolume == null) { return false; } // 可用空间可直接通过StorageVolume获取,返回值为应用可实际写入的字节数 long availableBytes = targetVolume.getAvailableBytes(); // 建议额外预留100MB缓冲区,避免系统临时文件占用导致空间不足 return availableBytes >= requiredSize + 100 * 1024 * 1024; } catch (Exception e) { // 异常场景包括Uri无效、权限被回收等,可根据业务逻辑自行处理 return false; } }
低版本降级兼容方案
如果你的应用需要兼容Android 7.0以下设备,没有可适配的标准API,推荐采用以下降级逻辑:
- 跳过前置空间校验,写入文件时捕获
IOException,如果异常原因为空间不足,再弹窗提示用户清理存储空间 - 禁止手动解析Uri的路径字符串拼接为
File对象,不同系统版本、不同ROM的Uri规则存在差异,这类方法稳定性极低
注意事项
- 不要使用
StorageStatsManager等仅支持File对象的API,分区存储下无法通过Uri转换得到合法的File对象 - 不要硬编码解析
content://com.android.externalstorage.documents/xxx这类Uri的路径段,系统版本迭代后规则可能变化,会导致适配失败 - 写入1GB以上大文件时建议分块写入,每写入100MB左右刷入磁盘一次,避免单次写入过大导致OOM或者写入失败无法回滚
内容的提问来源于stack exchange,提问作者laim2003
相关产品推荐
相关产品推荐

