Android内部存储与外置SDCard

Android手机存储
通常有三个部分
1、Ram
Ram 也就是相当于PC内存条的东东,没什么好说的。


2、手机存储
手机内通常内置一块eMMC存储设备,也就是常说的Rom。个人觉得这个Rom就相当于PC的硬盘。


其实,手机自带存储叫Rom有点过时了,所谓的“ROM是只读内存(Read-Only Memory)的简称。ROM所存数据,一般是装入整机前事先写好的,整机工作过程中只能读出,而不像随机存储器那样能快速地、方便地加以改写。ROM所存数据稳定 ,断电后所存数据也不会改变;其结构较简单,读出较方便,因而常用于存储各种固定程序和数据”。在Android之前的手机,包括智能机(Nokia、WM等)和非智能机(索爱,Moto P2K平台,MTK等)都有一个单独的ROM芯片保存系统文件。
系统区存储
随着这块芯片的存储容量越来越大,如今的手机很多都进行了分区。一部分相当于以前的Rom,相对于PC就好像是windows的C盘一样,但依然是可写的,用于存储系统,以及安装的程序。“data/data/包名”目录下可存储应用的私有数据,其它应用没有权限读写。
虚拟SD卡(通常说的内部存储)
这是eMMC芯片的另一部分,相当于PC的D盘,至于可不可以把eMMC芯片分更多区,这个没有找到相关资料,也没有发现这样的设备,应该暂时不用管吧。


3、外部存储
也就是外置的SDcard这些东东。




介绍了Android手机的存储情况,那么问题来啦。
都知道取SDcard的路径用的是Android提供的接口 Environment.getExternalStorageDirectory(),但是接口只有一个,取到的是虚拟的SDcard,还是真正的外置SDcard就不知道了。实际上两个都有可能,不同的手机产商得到的结果会不一样。如何取到另一个以及如何知道哪个是真正的外置SDcard。
方法一:通过分析mount指令的返回结果(百度来的,网址不记得了)
public static String[] getAllSDCard() {
String s = "";
try {
Process process = new ProcessBuilder().command("mount")

       .redirectErrorStream(true).start();

process.waitFor();

InputStream is = process.getInputStream();
byte[] buffer = new byte[1024];
while (is.read(buffer) != -1) {
   s = s + new String(buffer);
}
is.close();
} catch (Exception e) {
e.printStackTrace();
}


//用行分隔mount列表
String[] lines = s.split("\n");
for(int i=0; i<lines.length; i++) {
//如果行内有挂载路径且为vfat类型,说明可能是内置或者外置sd的挂载点
if(-1 != lines[i].indexOf("sdcard") && -1 != lines[i].indexOf("vfat")) {
   //再用空格分隔
   String[] blocks = lines[i].split("\\s");
   for(int j=0; j<blocks.length; j++) {
       //判断是否是挂载为vfat类型
       if(-1 != blocks[j].indexOf("sdcard")) {
           //Test if it is the external sd card.
       }
   }
}
}
return lines;
}


方法二:读系统文件,从文件中提取出来 (百度来的)
    public static Map<String, File> getAllStorageLocations() {
        Map<String, File> map = new HashMap<String, File>(10);


        List<String> mMounts = new ArrayList<String>(10);
        List<String> mVold = new ArrayList<String>(10);
        mMounts.add("/mnt/sdcard");
        mVold.add("/mnt/sdcard");


        try {
            File mountFile = new File("/proc/mounts");
            if(mountFile.exists()){
                Scanner scanner = new Scanner(mountFile);
                while (scanner.hasNext()) {
                    String line = scanner.nextLine();
                    if (line.startsWith("/dev/block/vold/")) {
                        String[] lineElements = line.split(" ");
                        String element = lineElements[1];


                        // don't add the default mount path
                        // it's already in the list.
                        if (!element.equals("/mnt/sdcard"))
                            mMounts.add(element);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }


        try {
            File voldFile = new File("/system/etc/vold.fstab");
            if(voldFile.exists()){
                Scanner scanner = new Scanner(voldFile);
                while (scanner.hasNext()) {
                    String line = scanner.nextLine();
                    if (line.startsWith("dev_mount")) {
                        String[] lineElements = line.split(" ");
                        String element = lineElements[2];


                        if (element.contains(":"))
                            element = element.substring(0, element.indexOf(":"));
                        if (!element.equals("/mnt/sdcard"))
                            mVold.add(element);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }




        for (int i = 0; i < mMounts.size(); i++) {
            String mount = mMounts.get(i);
            if (!mVold.contains(mount))
                mMounts.remove(i--);
        }
        mVold.clear();


        List<String> mountHash = new ArrayList<String>(10);


        for(String mount : mMounts){
            File root = new File(mount);
            if (root.exists() && root.isDirectory() && root.canWrite()) {
                File[] list = root.listFiles();
                String hash = "[";
                if(list!=null){
                    for(File f : list){
                        hash += f.getName().hashCode()+":"+f.length()+", ";
                    }
                }
                hash += "]";
                if(!mountHash.contains(hash)){
                    String key = "SD_CARD" + "_" + map.size();
                    if (map.size() == 0) {
                        key = "SD_CARD";
                    } else if (map.size() == 1) {
                        key = "EXTERNAL_SD_CARD";
                    }
                    mountHash.add(hash);
                    map.put(key, root);
                }
            }
        }


        mMounts.clear();


        if(map.isEmpty()){
                 map.put("SD_CARD", Environment.getExternalStorageDirectory());
        }
        return map;
    }


事实上,方法一与方法二都可以取到当前挂载的SDcard列表,然而并不能区分是不是虚拟的。


可是系统自带的设置是可以区分,没有办法,只能去看设置的源码。在memory.java中,终于有了我想要的答案。
答案就在这里:
    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        final Context context = getActivity();
        mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
        mStorageManager = StorageManager.from(context);
        mStorageManager.registerListener(mStorageListener);
        addPreferencesFromResource(R.xml.device_info_memory);
        addCategory(StorageVolumePreferenceCategory.buildForInternal(context));
        final StorageVolume[] storageVolumes = mStorageManager.getVolumeList();
        for (StorageVolume volume : storageVolumes) {
            if (!volume.isEmulated()) {
                addCategory(StorageVolumePreferenceCategory.buildForPhysical(context, volume));
            }
        }
        setHasOptionsMenu(true);
    }


通过mStorageManager.getVolumeList()就可以得到存储器的列表,volume.isEmulated()可判断是不是虚拟的。一部分手机的isEmulated得到的都是false,结合isRemovable可得到更准确的判断。因为这些方法与类被SDK隐藏了,不能直接调用,所以只能通过java的反射机制了。
方法三:
public static void getAllStorages(Context c) {
StorageManager storageManager = (StorageManager) c
.getSystemService(Context.STORAGE_SERVICE);
try {
Class<?>[] paramClasses = {};
Method getVolumePathsMethod = StorageManager.class.getMethod(
"getVolumeList", paramClasses);
getVolumePathsMethod.setAccessible(true);
Object[] params = {};
Object[] invoke = (Object[]) getVolumePathsMethod.invoke(storageManager, params);
Class<?> volume = Class.forName("android.os.storage.StorageVolume");
Field[] fields = volume.getDeclaredFields();
for (Field f:fields) 
LOG.d(f.getName());
Field fieldPath = volume.getDeclaredField("mPath");
Field fieldEmulated = volume.getDeclaredField("mEmulated");
Field fieldRemove = volume.getDeclaredField("mRemovable");
fieldPath.setAccessible(true);
fieldEmulated.setAccessible(true);
fieldRemove.setAccessible(true);
for (int i = 0; i < invoke.length; i++) {
File filePath = (File) fieldPath.get(invoke[i]);
boolean emulated = fieldEmulated.getBoolean(invoke[i]);
boolean remove = fieldRemove.getBoolean(invoke[i]);
LOG.i("\npath : " + filePath.getPath() + "  isEmulated : " + emulated + "  isRemovable : " + remove);
}
} catch (Exception e) {
e.printStackTrace();
}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值