使用
StorageManager
,我们可以访问通过 USB OTG 连接到 Android 智能手机的可移动闪存驱动器:
val storageManager = context.getSystemService(Context.STORAGE_SERVICE) as StorageManager
storageManager.storageVolumes
.forEach { volume ->
Timber.d("uuid: ${volume.uuid}, storageUuid: ${volume.storageUuid}, path: ${volume.directory}, desc: ${volume.getDescription(context)}, state: ${volume.state}, isDir: ${volume.directory?.isDirectory}, isRemovable: ${volume.isRemovable}\nallocatedBytes: ${volume.storageUuid?.let { storageManager.getAllocatableBytes(it) }}")
}
例如:
#1 内置/内部主存储:
uuid: null
storageUuid: 41217664-9172-527a-b3d5-edabb50a7d69
path: /storage/emulated/0
desc: Internal storage
state: mounted
isDir: true
isRemovable: false
allocatedBytes: 33695051776
#2 USB 闪存盘:
uuid: 8013-83C4
storageUuid: null
path: /mnt/media_rw/8013-83C4
desc: ESD-USB
state: mounted
isDir: false
isRemovable: true
allocatedBytes: null // because storageUuid is null here
我们无法从
volumeEsdUsb.directory
获得可用空间:
#1 与
StatFs
会有例外:
val stats = StatFs(volumeEsdUsb.directory.absolutePath)
val freeSpace = stats.availableBlocksLong * stats.blockSizeLong
java.lang.IllegalArgumentException:无效路径: /mnt/media_rw/8013-83C4 位于 android.os.StatFs.doStat(StatFs.java:53) 在 android.os.StatFs.(StatFs.java:43)
#2 与
volumeEsdUsb.directory.usableSpace
它只会返回 0
有没有其他解决方案可以获取闪存驱动器上的可用空间,或者 Android 没有像盒子里的 USB 闪存驱动器这样的东西?
使用
Storage Access Framework
根本没有任何有关卷存储的信息,我们只需获取 treeUri
并将其与 Document
一起使用即可处理文件(创建、编辑、删除、移动、复制)
为您提供的信息
嗨,这可能是
StorageManager
的一个错误,但我还没有找到关于它的文档,但我们可以自己获取 storageUuid。
参见 StorageManager 的
StorageManager.convert
方法,它处理了 FAT 卷的简短 uuid 转换,格式为 XXXX-YYYY,并添加了前缀 StorageManager.FAT_UUID_PREFIX
。
但这是一个隐藏的方法。
搜索发现是
StorageManager.getUuidForPath
调用的。
听起来我们可以通过以下方式从中获取 uuid:
// That's your USB volume path
val file = File("/mnt/media_rw/8013-83C4")
val uuid = context.getSystemService<StorageManager>().getUuidForPath(file)
但不幸的是,它在我的测试中抛出了
FileNotFoundException
失败了。
也许你可以尝试一下。
如果不起作用,我们可以复制
StorageManager.convert
方法对 FAT 卷所做的操作,如下扩展:
/**
* This are copied from [StorageManager]
*/
private const val FAT_UUID_PREFIX = "fafafafa-fafa-5afa-8afa-fafa"
private fun isFatVolumeIdentifier(uuid: String): Boolean = uuid.length == 9 && uuid[4] == '-'
/**
* StorageVolume from [StorageManager].
* [StorageVolume.getStorageUuid] will return null when it is a usb FAT volume.
* [StorageVolume.getStorageUuid] SHOULD HAVE return with prefix [FAT_UUID_PREFIX] as in [StorageManager.convert].
* [storageUuidCompat] will do this for compat reason.
*/
@get:RequiresApi(Build.VERSION_CODES.N)
val StorageVolume.storageUuidCompat: UUID?
get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && storageUuid != null) {
storageUuid
} else if (uuid != null && isFatVolumeIdentifier(uuid!!)) {
UUID.fromString(FAT_UUID_PREFIX + uuid!!.replace("-", ""))
} else null
通过这种方法,我们可以获得空闲字节和总字节数:
val storageManager = context.getSystemService<StorageManager>()
val statesManager = context.getSystemService<StorageStatsManager>()
// 1. get free bytes by StorageStatesManager
val freeBytes = statesManager.getFreeBytes(storageVolume.storageUuidCompat)
// 2. get free bytes by StorageManager
val freeBytes2 = storageManager.getAllocatableBytes(storageVolume.storageUuidCompat)
val totalBytes = stateManager.getTotalBytes(storageVolume.storageUuidCompat)
totalBytes
是正确的,但对我来说 2 freeBytes
方法都得到 0。
您可以尝试一下,看看它是否适合您。
祝你好运。