当前位置: 首页 > article >正文

Android获取内置卡、内置U盘和挂载U盘路径和内存大小

开发一个功能需要使用内置卡、内置U盘和挂载U盘以及分别展示它们内存的大小。

使用的是反射机制,然而在获取外接U盘时发现永远获取导的U盘大小信息是一个固定值,这显示是不正确的,开始是完全使用path路径,后来发现使用internalpath获取U盘大小时是真实的,然而内置卡又没有这个路径,故最后根据不同类型分别选择使用这两个路径。

使用internalPath的大前提获取系统级别的权限:

android:sharedUserId="android.uid.system"

具体代码如下:

public static final String TYPE_INTERNAL_SD_CARD = "SD_Card";//内置卡
    public static final String TYPE_INTERNAL_T_CARD = "259";//内置T卡
    public static final String TYPE_U_DISK = "8";//U盘

/**
     * 获取内存大小 (其中path和internalPath为路径,实际看情况使用哪一个)
     *
     * @param context 上下文
     * @param uDisks  内置T卡(U盘)或外置U盘
     * @return String[] U盘信息,[0]U盘总内存大小 [1]U盘可用内存大小
     */
    public static long[] getUsbMemoryMsg(Context context, String uDisks) {
        String sdcardDir = null;
        StorageManager storageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
        Class<?> volumeInfoClazz = null;
        Class<?> diskInfoClazz = null;
        Class<?> storageVolumeClazz = null;
        long[] memory = new long[2];
        try {
            storageVolumeClazz = Class.forName("android.os.storage.StorageVolume");
            diskInfoClazz = Class.forName("android.os.storage.DiskInfo");
            Method isUsb = diskInfoClazz.getMethod("isUsb");
            volumeInfoClazz = Class.forName("android.os.storage.VolumeInfo");
            Method getType = volumeInfoClazz.getMethod("getType");
            Method getDisk = volumeInfoClazz.getMethod("getDisk");
            Method getDiskId = volumeInfoClazz.getMethod("getDiskId");
            Field path = volumeInfoClazz.getDeclaredField("path");//这个路径获取U盘大小时会出现大小固定为某一值的情况;这个路径可以获取内置盘
            Field internalPath = volumeInfoClazz.getDeclaredField("internalPath");//使用这个路径获取U盘大小就没有上述问题;内置盘没有这个路径
            Method getVolumes = storageManager.getClass().getMethod("getVolumes");
            Method getUserLabel = storageVolumeClazz.getMethod("getUserLabel");
            Method getVolumeList = storageManager.getClass().getMethod("getVolumeList");
            Object resultVolumeList = getVolumeList.invoke(storageManager);
            List<Class<?>> result = (List) getVolumes.invoke(storageManager);

            int resultVolumeListLength = Array.getLength(resultVolumeList);
            for (int i = 0; i < result.size(); ++i) {
                Object volumeInfo = result.get(i);
                Log.w("StorageUtils", "volumeInfo::" + JSON.toJSONString(volumeInfo));
                String labelInfo = null;
                Object disk;
                String diskId = null;
                if (i < resultVolumeListLength) {
                    disk = Array.get(resultVolumeList, i);
                    labelInfo = (String) getUserLabel.invoke(disk);
                }
                disk = getDisk.invoke(volumeInfo);
                diskId = (String) getDiskId.invoke(volumeInfo);
                Log.w("StorageUtils", "disk::" + JSON.toJSONString(disk));
                Log.w("StorageUtils", "diskId::" + diskId + ",,disk-path::" + path.get(volumeInfo) + ",," + (labelInfo == null ? "unknown" : labelInfo));
                Log.w("StorageUtils", "uDisks::" + uDisks);
                sdcardDir = (String) path.get(volumeInfo);
                Log.w("StorageUtils ", "sdcardDir::" + sdcardDir);
                //内置卡没有disk对象,有两个路径  /data和/storage/emulated只读一个即可
                if (uDisks.equals(StorageUtils.TYPE_INTERNAL_SD_CARD) && diskId == null && sdcardDir.contains("/storage")) {
                    long total = getTotalExternalStorageSize(sdcardDir);
                    long available = getAvailableExternalStorageSize(sdcardDir);
                    memory[0] = total;
                    memory[1] = available;
                    Log.w("StorageUtils", "sdCard::total::" + total + ",,available::" + available + ",,internalPath::" + internalPath);
                    return memory;
                }
                //U盘类型(内置T卡)+U盘
                if (diskId != null && diskId.contains(uDisks) && disk != null && (Boolean) isUsb.invoke(disk)) {
                    //使用internalPath代替path后没有上述问题
                    sdcardDir = (String) internalPath.get(volumeInfo);
                    long total = getTotalExternalStorageSize(sdcardDir);
                    long available = getAvailableExternalStorageSize(sdcardDir);
                    memory[0] = total;
                    memory[1] = available;
                    Log.w("StorageUtils", "total::" + total + ",,available::" + available + ",,internalPath::" + sdcardDir);
                    return memory;
                }
            }
            return null;
        } catch (Exception var22) {
            Log.i("StorageUtils", "usb-path e " + var22.getMessage());
            var22.printStackTrace();
            Log.w("StorageUtils", "usb-path null");
            return null;
        }
    }


/**
     * 获取总内存
     */
    public static long getTotalExternalStorageSize(String storagePath) {

        StatFs statFs = new StatFs(storagePath);
        long blockSize = statFs.getBlockSizeLong();
        long totalBlocks = statFs.getBlockCountLong();
        Log.d(TAG, "blockSize:" + blockSize);
        Log.d(TAG, "totalBlocks:" + totalBlocks);
        return totalBlocks * blockSize;
    }

    /**
     * 获取剩余内存
     */
    public static long getAvailableExternalStorageSize(String storagePath) {
        StatFs statFs = new StatFs(storagePath);
        long blockSize = statFs.getBlockSizeLong();
        long availableBlocks = statFs.getAvailableBlocksLong();
        Log.d(TAG, "blockSize:" + blockSize);
        Log.d(TAG, "availableBlocks:" + availableBlocks);
        return availableBlocks * blockSize;
    }

上述代码中打印的volumeInfo参数信息如下:仅供参考

///内置卡
{
    "description": "内部共享存储空间",
    "id": "private",
    "mountUserId": -10000,
    "mountedReadable": true,
    "mountedWritable": true,
    "path": "/data",
    "primary": false,
    "primaryPhysical": false,
    "state": 2,
    "type": 1,
    "visible": false
}
///内置T卡
{
    "disk": {
        "adoptable": false,
        "defaultPrimary": false,
        "description": "0x144d U 盘",
        "flags": 8,
        "id": "disk:259,0",
        "label": "0x144d",
        "sd": false,
        "shortDescription": "U 盘",
        "size": 1000204886016,
        "stability": 0,
        "stubVisible": false,
        "sysPath": "/sys//devices/platform/fe150000.pc/nvme/nvme0/nvme0n1",
        "usb": true,
        "volumeCount": 1
    },
    "diskId": "disk:259,0",
    "fsLabel": "",
    "fsType": "vfat",
    "fsUuid": "1EDB-1816",
    "id": "public:259,1",
    "internalPath": "/mnt/media_rw/1EDB-1816",
    "mountFlags": 2,
    "mountUserId": 0,
    "mountedReadable": true,
    "mountedWritable": true,
    "normalizedFsUuid": "1edb-1816",
    "partGuid": "",
    "path": "/storage/1EDB-1816",
    "primary": false,
    "primaryPhysical": false,
    "stability": 0,
    "state": 2,
    "stateDescription": 17040185,
    "type": 0,
    "visible": true
}

///U盘
{
    "description": "新加卷  \b",
    "disk": {
        "adoptable": false,
        "defaultPrimary": false,
        "description": "Kingston U 盘",
        "flags": 8,
        "id": "disk:8,0",
        "label": "Kingston",
        "sd": false,
        "shortDescription": "U 盘",
        "size": 31029460992,
        "stability": 0,
        "stubVisible": false,
        "sysPath": "/sys//devices/platform/usbdrd3_0/fc000000.usb/xhci-hcd.7.auto/usb9/9-1/9-1:1.0/host0/target0:0:0/0:0:0:0/block/sda",
        "usb": true,
        "volumeCount": 1
    },
    "diskId": "disk:8,0",
    "fsLabel": "新加卷  \b",
    "fsType": "vfat",
    "fsUuid": "720F-AFA1",
    "id": "public:8,1",
    "internalPath": "/mnt/media_rw/720F-AFA1",
    "mountFlags": 2,
    "mountUserId": 0,
    "mountedReadable": true,
    "mountedWritable": true,
    "normalizedFsUuid": "720f-afa1",
    "partGuid": "",
    "path": "/storage/720F-AFA1",
    "primary": false,
    "primaryPhysical": false,
    "stability": 0,
    "state": 2,
    "stateDescription": 17040185,
    "type": 0,
    "visible": true
}

U盘插入拔出状态监听广播:

广播接收U盘插入拔出状态和路径_安卓接收到u盘插入的广播之后,怎么判断已经插入-CSDN博客


http://www.kler.cn/a/419412.html

相关文章:

  • STL:相同Size大小的vector和list哪个占用空间多?
  • SpringCloud2~~~
  • WRF-Chem模式安装、环境配置、原理、调试、运行方法;数据准备及相关参数设置方法
  • 【Electron学习笔记(三)】Electron的主进程和渲染进程
  • ros sensor_msgs::Imu详细介绍 Eigen::Vector3d 详细介绍
  • 互联网基础
  • Lerna管理和发布同一源码仓库的多个js/ts包
  • React面试进阶(五)
  • docker rocketmq
  • vue2和vue3两种倒计时CountDown实现
  • 设计模式之单例
  • Leetcode - 周赛425
  • EditInPlace就地编辑:Dom vs Form
  • 缓存与缓冲
  • 基于PHP的音乐网站的设计与实现
  • 每日速记10道java面试题03
  • 写一份客服网络安全意识培训PPT
  • 如何分段存储Redis键值对
  • 智慧银行反欺诈大数据管控平台方案(二)
  • windows C#-为类或结构定义值相等性(上)
  • 网络原理-初识
  • 解密开源大模型如何实现本地化部署并基于本地的知识库进行应用
  • Java基础面试题11:简述System.gc()和Runtime.gc()的作用?
  • 一些面试问题的深入与思考
  • 国际网络安全趋势
  • git push使用