如何在安卓设备上读取USB设备中的文件?

6
我正在尝试通过连接的USB设备(通过OTG或Android TV上的USB端口)创建类似文件浏览器的东西。我所需要的只是像“/storage/sda4”这样的路径和设备标识符,然后我就可以通过简单的android文件类来处理设备。听起来很简单,但我找不到任何关于此的信息,但所有文件浏览器都可以做到(例如ESExplorer)。好的,我找到了一种获取所有已连接的带有标识符的USB设备的简单方法。
UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
usbManager.getDeviceList();

但是我如何获取路径信息呢?deviceName包含类似于“/dev/bus/usb/00x”的内容,但这并不能帮助我,我需要简单的模拟Android路径(“/storage/sda4”)。此页面https://developer.android.com/guide/topics/connectivity/usb/host.html告诉我需要获取UsbInterfaces并进行UsbConnection以进行批量传输和其他废话,我已经完成了所有操作,但没有找到设备路径或有关USB文件列表的任何其他信息。

好吧,我找到了另一种方法(不需要权限!)来获取所有连接设备的路径。

StorageManager storageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
Method getVolumeListMethod = StorageManager.class.getDeclaredMethod("getVolumeList");
Object[] storageVolumeList = (Object[]) getVolumeListMethod.invoke(storageManager);

并且它能够工作,但我需要识别设备(因为我想缓存不同USB存储的文件),但从卷对象中获取的所有内容仅有mStorageId、mDescriptionId、mPrimary、mRemovable、mEmulated、mMtpReserveSpace、mAllowMassStorage、mMaxFileSize、mOwner、mUuid、mUserLabel、mState和mSubSystem。这些都不能识别设备:mDescriptionId和mStorageId对于USB端口是唯一的,mUuid为空,mUserLabel不唯一。
Environment.getExternalFilesDirs()无法帮助,它不提供任何设备ID,而且仅适用于一个设备。
我在这里找到了一个类似的问题,但没有正确答案:Android list files from USB Drive
那么,是否存在一种简单的方法可以获取带有路径和标识符的USB设备列表?

看一下 getExternalFilesDirs()。第三个条目将是OTG USB驱动器。 - greenapps
我刚刚编辑了这个问题,我提到了getExternalStorageDirectory而不是getExternalFilesDirs。 它不提供任何设备标识符。 - LamaUltramarine
如果你想制作一个文件浏览器,你为什么需要设备ID呢?你只需要路径。而getExternalFilesDirs()将提供给你这个。不要说它做不到! - greenapps
它为不同的USB驱动器提供了不同的路径。驱动器ID在路径中,例如/ADAE-12FE/。 - greenapps
@ greenapps 问题是,每次插入 USB 时文件路径都会改变。 - Utsav Gupta
显示剩余2条评论
1个回答

6
我所需要的只是一个类似于“/storage/sda4”的路径和设备标识符,然后我就可以通过简单的Android类文件来处理设备。
不行,因为在Android 4.4+上,您无法任意访问可移动存储设备,包括USB OTG驱动器。
所有文件浏览器都可以做到这一点(例如ESExplorer)。
预装的“文件浏览器”应用程序可能会被设备制造商或自定义ROM开发人员授予其他权限。否则,它们也无法任意访问可移动存储。
有没有一种简单的方法可以获取带有路径和标识符的USB设备列表?
没有使用文件系统路径的方法。StorageManager上的getStorageVolumes()将给您一个存储卷列表,其中包括外部存储和可移动存储。然后,您可以在StorageVolume上使用createAccessIntent()来请求用户对该卷进行操作的权限。如果他们授权,则会返回一个Uri:
  • 作为卷的临时标识符(例如,如果用户弹出媒体,则不再可用作标识符,但在此之前,可以将一个卷与另一个区分开),并且

  • 让您使用Uri值而不是文件系统路径来处理该卷的部分内容


非常感谢您提供详细的答案。我尝试使用getStorageVolumes,但它需要24个API及更高版本,但目前还没有普及开来。在看了您的回答后,我明白唯一的方法就是我所描述的第二种方式,它可以为我提供所有设备的路径,并且我可以使用简单的File类进行操作(我已经在Android 5和5.1上测试过:)也许这是Android的缺陷,但这是事实。我将使用mUserLabel作为ID,在大多数情况下是唯一的。 - LamaUltramarine
StorageManager storageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE); Method getVolumeListMethod = StorageManager.class.getDeclaredMethod("getVolumeList"); Object[] storageVolumeList = (Object[]) getVolumeListMethod.invoke(storageManager); 我使用这些代码获取存储卷列表,但我只得到了 /storage/emulated/0 ,而我的 OTG 连接了一个闪存驱动器。为什么我没有获取到 OTG 连接设备的路径? - Anupriya
@Anupriya:可能是因为您正在使用反射来获取在您运行的Android版本上不支持的内容。 - CommonsWare
@Anupriya 你是为每个对象都做了这个吗?我在Android 4.4.+上测试过,它可以在任何地方工作:Field pathField = object.getClass().getDeclaredField("mPath"); pathField.setAccessible(true); Object pathObject = pathField.get(object); - LamaUltramarine
1
@kb_14:厂商可能会自己处理USB存储,这只是我的猜测。这个设备有SD卡插槽吗?如果有的话,如果你插入一张卡,它是否会在getStorageVolumes()中显示出来? - CommonsWare
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接