Android OTG 读写U盘文件

最近项目需要做一个关于OTG的功能,其实也就使用到U盘的文件读取,一般这种需求是不需要的,因为大部分的系统都会自动挂载U盘,但是个别系统还是需要自己去实现,查了很多资料都没有找到一个完整的能用的例子,要么就是年代偏远,好不容易运行起来跑不了,或者没效果,这个过程是很烦的,google了一下后,发现了一个开源的文件管理器,但是该管理器在使用的时候却出现了OTG无法读取的问题,详细的话可以自己去看看 GitHub - 1hakr/AnExplorer: 📁 Another Android Explorer ( File Manager ) is an All-in-One Open source file manager. AnExplorer File Manager (File Explorer) is designed for all android devices including Phones, Phablets, Tablets, Chromecast, Wear OS, Android TV and Chromebooks. It's a fully designed with Material guidelines by Google.,我是去看源码它的USB实现过程中从中提取了一部分东西,再结合看的其他博客,总算能实现读写的效果。
阅读之前,可先看一下这几篇文章了解一些概念:

android-USB-OTG 外部设备通讯 USB插拔检测

Android实战技巧之四十九:Usb通信之USB Host

https://developer.android.com/guide/topics/connectivity/usb/host.html

    好吧,其实看了也只是有个大概的了解,要想实现其实还是差了点,特别是获取U盘目录什么的简直不知道该怎么下手,废话不多说,看一下个人实现,如果你有更好的实现,欢迎留言讨论。

    首先,肯定需要获取读取OTG和文件权限,在manifest.xml中加入以下权限

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.hardware.usb.host" android:required="false" />

    然后,部分手机上是没有otg的所以需要加入特性。

 <uses-feature android:name="android.hardware.usb.host" android:required="true" /> 

    有了权限后,就可以开始编码了。

    第一步,注册广播,监听otg插拔事件。

//监听otg插入 拔出
IntentFilter usbDeviceStateFilter = new IntentFilter();
usbDeviceStateFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
usbDeviceStateFilter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
//注册监听自定义广播
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
registerReceiver(mUsbReceiver, filter);

    ACTION_USB_PERMISSION是定义的一个权限字段

private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";

    接上

    //otg插入 拔出广播
    getActivity().registerReceiver(mUsbReceiver, usbDeviceStateFilter);//这里我用的碎片
    registerReceiver(mUsbReceiver, usbDeviceStateFilter);//这里我用的碎片
    //mUsbReceiver只是一个普通的广播,根据action,去分别处理对应的事件。
    private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            switch (action) {
                case ACTION_USB_PERMISSION://接受到自定义广播
                    synchronized (this) {
                        UsbDevice usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                        if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { //允许权限申请
                            if (usbDevice != null) {
                                //Do something
                            }
                        } else {
                            TShow("用户未授权,读取失败");
                        }
                    }
                    break;
                case UsbManager.ACTION_USB_DEVICE_ATTACHED://接收到存储设备插入广播
                    UsbDevice device_add = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                    if (device_add != null) {
                        TShow("接收到存储设备插入广播");
                    }
                    break;
                case UsbManager.ACTION_USB_DEVICE_DETACHED://接收到存储设备拔出广播
                    UsbDevice device_remove = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                    if (device_remove != null) {
                        TShow("接收到存储设备拔出广播");
                        //拔出或者碎片 Activity销毁时 释放引用
                        //device.close();
                    }
                    break;
            }
        }
    };

    TShow()是我个人的Toast消息封装,上述中的广播每一个都可以获取到usb设备的实体信息类,可以根据个人逻辑处理。

    第二步,枚举设备

        //获取管理者
        UsbManager usbManager = (UsbManager) getContext().getSystemService(Context.USB_SERVICE);
        //枚举设备
        UsbMassStorageDevice[] storageDevices = UsbMassStorageDevice.getMassStorageDevices(getContext());//获取存储设备
        PendingIntent pendingIntent = PendingIntent.getBroadcast(getActivity(), 0, new Intent(ACTION_USB_PERMISSION), 0);
        for (UsbMassStorageDevice device : storageDevices) {//可能有几个 一般只有一个 因为大部分手机只有1个otg插口
            if (usbManager.hasPermission(device.getUsbDevice())) {//有就直接读取设备是否有权限
                read(device);
            } else {//没有就去发起意图申请
                usbManager.requestPermission(device.getUsbDevice(), pendingIntent); //该代码执行后,系统弹出一个对话框,
            }
        }

    申请意图执行后,会进入上面的广播中,然后,在需要处理的地方去执行读取操作。

    第三步,读取U盘信息

    这里需要说明一下,UsbMassStorageDevice这个类来自开源库,里面包含了一些获取大容量存储设备的操作和其他封装。可以在Gradle中加入依赖:

        compile 'com.github.mjdev:libaums:+'

该库GitHub地址:https://github.com/magnusja/libaums#using-buffered-streams-for-more-efficency

    read(device);的详细代码:

private void read(UsbMassStorageDevice massDevice) {
            // before interacting with a device you need to call init()!
            try {
                massDevice.init();//初始化
                //Only uses the first partition on the device
                Partition partition = massDevice.getPartitions().get(0);
                FileSystem currentFs = partition.getFileSystem();
                //fileSystem.getVolumeLabel()可以获取到设备的标识
                //通过FileSystem可以获取当前U盘的一些存储信息,包括剩余空间大小,容量等等
                Log.d(TAG, "Capacity: " + currentFs.getCapacity());
                Log.d(TAG, "Occupied Space: " + currentFs.getOccupiedSpace());
                Log.d(TAG, "Free Space: " + currentFs.getFreeSpace());
                Log.d(TAG, "Chunk size: " + currentFs.getChunkSize());
                UsbFile root = currentFs.getRootDirectory();
            } catch (Exception e) {
                e.printStackTrace();
                TShow("读取失败");
            }
    }

    到这里就已经可以获取到U盘根目录的实体类UsbFile了 

    UsbFile的部分函数:

listFiles();//该函数可以获取到某个目录下所有的文件

boolean isDirectory();//判断是否是目录

void setName(String newName) throws IOException//给目录或文件设置名称

String getName();//获取该文件或目录的名称

UsbFile getParent();//该函数可以获取父类对象,比如根目录是root,它有个子目录music,那么通过music的UsbFile对象可以获取到root的文件和目录列表,也就解决了获取上一级目录文件的问题。    

long getLength();//如果是个文件,可以获取到文件大小

void read(long offset, ByteBuffer destination) throws IOException;//文件读取操作

void write(long offset, ByteBuffer source) throws IOException;//文件写入操作

UsbFile createDirectory(String name) throws IOException;//如果是个目录,那么会在该目录下创建一个新的目录

UsbFile createFile(String name) throws IOException;//如果该目录存在,会在该目录下生成一个新的文件

void delete() throws IOException;//文件和目录删除操作

boolean isRoot();//当前目录是否是根目录

    常用的函数就这几个,基本上包括了U盘文件的增删改查,如果说需要一个File的对象,那么可以通过流的形式进行先保存到本地再获取。因为File对象指向了一个具体的uri地址,也就是说,必须要有能访问的具体路径,比如内置存储和sd卡的目录。

    具体步骤:先创建一个具体的文件,然后以io形式进行文件写入,相当于复制,io完成后即可获取File对象

    如下:       

 new Thread(new Runnable() {
              @Override
              public void run() {
                  try {
                      FileOutputStream os = new FileOutputStream(tempFile);
                      InputStream is = new UsbFileInputStream(usbFile);
                      int bytesRead = 0;
                      byte[] buffer = new byte[1024 * 8];//作者的推荐写法是currentFs.getChunkSize()为buffer长度
                      while ((bytesRead = is.read(buffer)) != -1) {
                          os.write(buffer, 0, bytesRead);
                      }
                      os.flush();
                      os.close();
                      is.close();
                      //Do something
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
              }

          }).start();

    好了,基本上整个流程就是这样的,由于百度账户注销了,所以源码没了,但是只要看懂了这个流程基本上就没什么问题了。

  • 14
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 75
    评论
### 回答1: Android U盘读写是指在Android系统设备上使用U盘进行数据传输和存储的过程。在Android系统中,U盘通常使用USB接口与设备连接,通过USB On-The-Go(简称USB OTG)技术可以使设备拥有读写U盘的能力。 要在Android设备上读写U盘,首先需要确保设备支持USB OTG功能,并且安装了相应的驱动程序。然后将U盘插入设备的USB接口,系统会自动识别U盘,并在文件管理器中显示其中的文件文件夹列表。接着就可以像在电脑上操作一样进行文件的拷贝、移动、删除等操作了。 需要注意的是,不同设备对U盘读写的支持程度可能有所不同。有些设备可能只能读取U盘中的文件,而不能写入,或者只能写入部分格式的文件。此外,U盘的格式也会影响设备的读写能力。因此,在使用之前需要先了解设备和U盘的限制,以避免数据丢失或损坏。 总的来说,Android U盘读写功能的便利性和灵活性使其成为很多人进行数据传输和备份的首选方式。对于需要频繁进行数据交换的用户来说,它的作用是不可替代的。 ### 回答2: 对于android u盘读写,首先需要保证你的android设备支持OTG(On-The-Go)功能。 如果你的设备支持OTG,可以通过OTG线连接U盘android设备,然后直接在安卓设备上找到文件管理器,就能看到u盘的存储设备了。 接下来,你可以打开文件管理器,浏览U盘中的文件,并进行读写操作。如果需要复制文件U盘,则直接在文件管理器中选择要复制的文件,然后将其粘贴到U盘的根目录或指定文件夹下即可。同样,如果需要从U盘中复制文件android设备,则选择要复制的文件,将其粘贴到想要存储的android设备文件夹下即可。 需要注意的是,在android设备上对于U盘进行读写操作时,需要牢记安全移除U盘的步骤,否则会将数据损坏。 总的来说,使用OTG线连接U盘android设备,通过文件管理器进行读写操作是十分方便的,因此在出门旅行时,将重要文件存储在U盘中,即可随时实现安卓设备和电脑之间的数据互传。 ### 回答3: Android设备上的U盘读写操作并不像在电脑上那么简单,需要一些必要的前置条件。首先,您需要连接一根OTG(On-The-Go)线缆将U盘Android设备连接起来。OTG线缆的一端是一个Micro USB端口,另一端是一个USB2.0或3.0端口,您应该根据自己的设备来选择合适的线缆类型。 接下来,当您连接U盘后,您的Android设备或许会出现一个提示框,问您想如何处理连接的U盘,这将由您自己决定。然后,您需要查看U盘是否已经正确识别,可以在“文件管理器”应用程序中看到U盘是否出现在文件列表中。如果您不能看到它,请尝试断开连接并重新连接U盘,或者重启您的Android设备并再次连接U盘。 此时您可以打开U盘并开始读写操作了。要复制文件U盘,请单击并长按要复制的文件,选择“复制”,然后进入U盘,再次单击并长按空白区域,选择“粘贴”完成文件复制。同样,您也可以使用相同的方法将U盘上的文件复制到Android设备上,只需要选择粘贴的目标是您的设备内存或SD卡即可。 但是,需要注意的是,在进行读写U盘操作时,请勿在拔出U盘之前来回插拔U盘,否则可能会导致文件损坏。在不需要使用时,应该先卸载U盘,然后再从Android设备上断开连接。
评论 75
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值