Android 获取外接储存的设备路径(如挂载的U盘)

本文介绍了如何在Android系统中通过监听开机及U盘挂载事件获取U盘路径的方法。包括静态注册广播接收器来监听开机完成及U盘挂载、拔除事件,以及通过Linux命令获取U盘挂载路径。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前提介绍:项目中遇到这样一种情况,需要在开机和插入U盘的时候去获取U盘的路径,并读取U盘中的一个文件。其中插入U盘的时候,直接监听U盘挂载广播,可以获取U盘的路径,例如说路径A。但是开机的时候去需要找到U盘的路径,网上看了很多的例子,都不一样,获取的结果和上面的结果A都不一致,最后发现通过Linux可以获取挂载路径。
<转载请注明出处http://blog.youkuaiyun.com/Zou_pl/article/details/73743974>

  1. 插入U盘时获取U盘路径
  2. 开机时获取U盘路径

    首先是静态注册一个关于开机和挂载U盘的广播:

<receiver android:name=".receivers.USBReceiver">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
                <action android:name="android.intent.action.MEDIA_REMOVED"/>
                <action android:name="android.intent.action.MEDIA_MOUNTED"/>
                <action android:name="android.intent.action.MEDIA_REMOVED"/>
                <action android:name="android.intent.action.MEDIA_REMOVED"/>
                <data android:scheme="file"></data>
            </intent-filter>
        </receiver>

BOOT_COMPLETED:开机完成,而MEDIA_MOUNTED、MEDIA_REMOVED、MEDIA_REMOVED、MEDIA_REMOVED则是来获取U盘挂载、拔出等事件。
然后在广播接收者中依次处理这些事件:如下

public class USBReceiver extends BroadcastReceiver{

    private static final String TAG = USBReceiver.class.getSimpleName();

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if(action.equals(Intent.ACTION_MEDIA_MOUNTED)){
            String mountPath = intent.getData().getPath();
            Log.d(TAG,"mountPath = "+mountPath);
            if (!TextUtils.isEmpty(mountPath)) {
                //读取到U盘路径再做其他业务逻辑
            }
        } else if (action.equals(Intent.ACTION_MEDIA_UNMOUNTED) || action.equals(Intent.ACTION_MEDIA_EJECT)) {
            Toast.makeText(context, "No services information detected !", Toast.LENGTH_SHORT).show();
        } else if (action.equals("android.intent.action.BOOT_COMPLETED")) {
            //如果是开机完成,则需要调用另外的方法获取U盘的路径
        }
    }
}
先看一下通过intent.getData().getPath()获取的路径是什么:

这里写图片描述
可以看到打印的结果是:/mnt/sda/sda1

那么如果没有广播信息该如何获取对应的路径呢:利用Linux mount 命令。android也就是一种Linux系统,采用的是linux的内核。而linux中挂载存储设备使用的是 mount 命令来挂载设备到文件系统中。具体如下面代码:

public static List<String> getAllExternalSdcardPath() {
        List<String> PathList = new ArrayList<String>();

        String firstPath = Environment.getExternalStorageDirectory().getPath();
        Log.d(TAG,"getAllExternalSdcardPath , firstPath = "+firstPath);

        try {
        // 运行mount命令,获取命令的输出,得到系统中挂载的所有目录
            Runtime runtime = Runtime.getRuntime();
            Process proc = runtime.exec("mount");
            InputStream is = proc.getInputStream();
            InputStreamReader isr = new InputStreamReader(is);
            String line;
            BufferedReader br = new BufferedReader(isr);
            while ((line = br.readLine()) != null) {
                // 将常见的linux分区过滤掉
                if (line.contains("proc") || line.contains("tmpfs") || line.contains("media") || line.contains("asec") || line.contains("secure") || line.contains("system") || line.contains("cache")
                        || line.contains("sys") || line.contains("data") || line.contains("shell") || line.contains("root") || line.contains("acct") || line.contains("misc") || line.contains("obb")) {
                    continue;
                }

                // 下面这些分区是我们需要的
                if (line.contains("fat") || line.contains("fuse") || (line.contains("ntfs"))){
                    // 将mount命令获取的列表分割,items[0]为设备名,items[1]为挂载路径
                    String items[] = line.split(" ");
                    if (items != null && items.length > 1){
                        String path = items[1].toLowerCase(Locale.getDefault());
                        // 添加一些判断,确保是sd卡,如果是otg等挂载方式,可以具体分析并添加判断条件
                        if (path != null && !PathList.contains(path) && path.contains("sd"))
                            PathList.add(items[1]);
                    }
                }
            }
        } catch (Exception e){
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        if (!PathList.contains(firstPath)) {
            PathList.add(firstPath);
        }

        return PathList;
    }

上面是获取的具体方法:看一下打印
这里写图片描述

而上面方法中Environment.getExternalStorageDirectory().getPath()得到的结果是/mnt/shell/emulated。所以去掉这个路径就是我们想要的从插拔U盘广播的广播信息中获取的U盘路径信息一致。

<think>我们正在讨论Android平台上使用Java格式化外接存储设备(如U或SD卡)的问题。根据Android的存储架构,外接存储设备通常被挂载为可移动存储。在Android系统中,格式化存储设备通常需要系统级权限,并且普通应用程序无法直接执行格式化操作,因为这涉及到底层存储管理。 参考引用内容: -引用[1]提到Android的主存储概念,以及使用内置存储模拟外置存储的情况,还提到了加密机制(全加密和基于文件的加密)。 -引用[2]提到了i.MX8MPlusEVKAndroid12外部SD卡的自动挂载,使用dm-crypt加密,并格式化为ext4或f2fs文件系统。-引用[3]则提到了两个权限:`MASTER_CLEAR`(恢复出厂设置)和`MOUNT_FORMAT_FILESYSTEMS`(挂载和格式化文件系统)。其中,`MOUNT_FORMAT_FILESYSTEMS`权限正是我们格式化文件系统所需要的。 因此,要格式化外部存储设备,我们需要: 1.申请必要的权限:`android.permission.MOUNT_FORMAT_FILESYSTEMS`。注意,这是一个系统权限(protectionlevel为`signature`或`system`),普通应用无法使用,通常只有系统应用或具有系统签名的应用才能使用。 2.使用StorageManager的API来执行格式化操作。步骤:1.在AndroidManifest.xml中声明权限(如果应用是系统应用):```xml<uses-permissionandroid:name="android.permission.MOUNT_FORMAT_FILESYSTEMS"/>``` 2.使用StorageManager的`partitionPublic`方法来格式化存储设备为公共可访问的存储,或者使用`partitionPrivate`方法将其格式化为私有存储(需要加密)。但注意,这些方法在SDK中可能没有公开,因此可能需要通过反射调用,或者作为系统应用使用隐藏API。然而,从Android4.4(API19)开始,普通应用无法格式化外部存储设备。只有系统应用(安装在系统分区,具有系统签名)才能执行此操作。替代方案:-如果设备已root,可以通过执行命令行命令(如`newfs_msdos`或`mkfs`)来格式化,但这需要root权限,并且不是标准方法。因此,对于普通应用,格式化外部存储设备几乎是不可能的。但对于系统应用,可以尝试以下步骤: 作为系统应用格式化外部存储的步骤:1.获取StorageManager服务。2.获取要格式化的存储卷的ID(可以通过StorageVolume获取)。 3.调用StorageManager的`partitionPublic`或`partitionPrivate`方法。示例代码(系统应用):```javaStorageManager storageManager =(StorageManager)context.getSystemService(Context.STORAGE_SERVICE); //获取所有存储卷List<StorageVolume> storageVolumes= storageManager.getStorageVolumes();//遍历找到目标存储卷(例如通过路径或描述判断)StorageVolumetargetVolume= ...; //找到要格式化的U或SD卡对应的StorageVolumeStringvolumeId= targetVolume.getId(); //例如类似于"usb-1234"的ID//格式化公共存储(不加密)storageManager.partitionPublic(volumeId); //或者格式化私有存储(加密)// storageManager.partitionPrivate(volumeId); ```注意:`partitionPublic`和`partitionPrivate`是系统API,在普通应用的SDK中不可见。因此,系统应用可能需要使用反射或直接调用系统API(如果应用被编译为系统应用)。 另外,格式化操作会清除存储设备上的所有数据,必须谨慎操作。 对于普通应用,如果无法获得系统权限,可以考虑引导用户到系统设置中进行格式化。Android系统设置中提供了格式化SD卡的选项(在“存储”设置中)。可以通过Intent打开设置中的存储格式化界面,但Android并没有提供标准的Intent来直接打开格式化界面。因此,只能打开存储设置界面,让用户手动操作。总结: -普通应用:无法直接格式化外部存储设备,需要引导用户到系统设置中操作。 -系统应用:使用StorageManager的`partitionPublic`或`partitionPrivate`方法(需要声明系统权限`MOUNT_FORMAT_FILESYSTEMS`)。 相关问题: 1.如何在Android系统设置中格式化外部存储设备? 2.如何开发一个具有系统签名的Android应用?3.Android中如何通过反射调用系统隐藏API?4.如何获取外部存储设备的StorageVolume对象? 5. Android中外部存储设备的文件系统通常是什么格式?</think>### Android Java 格式化外部存储设备指南 在Android平台上格式化外接存储设备(如U或SD卡)需要特殊权限和系统级API,普通应用无法直接操作。以下是关键步骤和注意事项: #### 1. **必要权限声明** 需在`AndroidManifest.xml`中添加**系统级权限**(仅系统应用可用): ```xml <uses-permission android:name="android.permission.MOUNT_FORMAT_FILESYSTEMS" /> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" /> ``` > ⚠️ 这些权限的`protectionLevel="signature"`,仅授予系统签名应用[^3]。 #### 2. **格式化实现步骤** ```java // 获取StorageManager服务 StorageManager storageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE); // 获取目标存储卷(SD卡/U) StorageVolume targetVolume = null; for (StorageVolume volume : storageManager.getStorageVolumes()) { if (volume.isRemovable() && volume.getState().equals(Environment.MEDIA_MOUNTED)) { targetVolume = volume; // 根据实际路径筛选 } } // 执行格式化(需反射调用系统API) try { Method partitionPublic = StorageManager.class.getMethod("partitionPublic", String.class); partitionPublic.invoke(storageManager, targetVolume.getId()); // 格式化为公共存储 } catch (Exception e) { e.printStackTrace(); } ``` #### 3. **关键限制说明** - **系统应用要求**:必须预置到系统分区或使用平台签名 - **加密机制**:Android 7.0+默认启用基于文件的加密(FBE),外置存储可能被强制加密[^1] - **文件系统类型**:通常格式化为FAT/exFAT(兼容性)或ext4/f2fs(性能优化)[^2] - **用户数据安全**:格式化会**永久删除所有数据**,无恢复可能 #### 4. **替代方案(普通应用)** 普通应用可通过以下间接方式: 1. **引导用户手动操作**: ```java Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(Uri.parse("content://com.android.settings.files/my_usb")); startActivity(intent); // 跳转系统存储设置 ``` 2. **ADB命令实现**(需root): ```bash adb shell sm partition disk:XXX,YYY public # 格式化公共存储 ``` > 📌 **最佳实践**:设备制造商实现时,需在内核层配置自动挂载规则(如i.MX8MPlus的`android_ext`分区)[^2]。 --- ### 相关问题 1. Android系统应用如何获取平台签名? 2. 不同文件系统(FAT32/exFAT/ext4)在Android存储中的性能差异? 3. 如何通过Android的StorageManager动态监控外置存储状态? 4. Android 13的Scoped Storage对外置存储访问有何新限制? 5. 系统级格式化操作如何避免误删用户数据的安全设计? [^1]: Android主存储机制与加密策略 [^2]: i.MX8MPlus的外部存储实现方案 [^3]: Android系统级存储操作权限声明
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值