通过USB OTG获取连接的USB驱动器的可用空间

问题描述 投票:0回答:1

使用

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
一起使用即可处理文件(创建、编辑、删除、移动、复制)

android android-file android-storage android-usb
1个回答
0
投票

为您提供的信息

嗨,这可能是

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。

您可以尝试一下,看看它是否适合您。

祝你好运。

© www.soinside.com 2019 - 2024. All rights reserved.