1.存储空间简介

Android存储空间主要分为三个部分:内存、机身存储和SD卡存储。内存用于程序计算,通常空间小,速度快而造价高。机身存储和SD卡存储可以用于保存文件,如照片、视频等。机身存储和SD卡存储不能用于程序计算,但是可以在断电时保存文件,空间大且造价小。所以内存和机身存储、SD卡存储的任务是不同的。在支持扩展存储空间的手机上,如果机身自带存储空间不够,可以插入SD卡来扩大空间。类比于电脑来说,手机内存相当于电脑内存条,机身存储相当于硬盘,而SD卡存储相当于可移动硬盘。机身存储和SD卡存储都不能用来进行程序计算,都是外存。


2.SD卡路径获取及手机内存路径获取

       Android提供了一种获取存储路径的方法如下:

        

      

Environment.getExternalStorageDirectory().getAbsolutePath();//方法A

     

从名字上看,我们很容易会认为该方法就是获取外置SD卡的方法,这里我写了一个小程序做验证,同时使用这种方法和另外一种方法来获取路径。为了描述方便,上述方法下文称其为方法A,另一种接下来要介绍的方法称其为方法B。验证结果如下图:

android 存储分区 android 存储空间分析_内存

图1

图1中的external路径是我用方法A获取到的路径,SD卡路径及机身存储路径是我用方法B获取到的。从图中可以看到,方法A获取到的是机身存储路径,而不是SD卡路径。由此看来,external在这里的含义就是外部存储,而并不是说获取的是SD卡路径。根据网上查阅的资料知,该方法由于厂商的不同,有的品牌手机上获取到的是机身存储路径,有的品牌手机上获取到的是SD卡路径。所以,想通过方法A来获取到正确的SD卡路径或机身存储路径是不可靠的。

    接下来我们来介绍一下正确的SD卡路径及机身存储路径获取方法,主要分为以下两步:

    (1)获取所有挂载的存储设备

           a.先定义一个StorageInfo类记录每个挂载的存储设备的信息,信息包括路径,状态,是否可移除等。代码如下:               


<span >	</span>public class StorageInfo {
		public String path;
		public String state;
		public boolean isRemoveable;

		public StorageInfo(String path) {
			this.path = path;
		}

		public boolean isMounted() {
			return "mounted".equals(state);
		}
	}



 

getVolumeList来获取到所有挂载的存储设备,并记录存储设备信息。具体代码如下,最后返回一个存储设备信息列表:

   

public  List getAvaliableStorage(Context context) {
	        ArrayList storages = new ArrayList();
	        StorageManager storageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
	        try {
	            Class<?>[] paramClasses = {};
	            Method getVolumeList = StorageManager.class.getMethod("getVolumeList", paramClasses);
	            getVolumeList.setAccessible(true);
	            Object[] params = {};
	            Object[] invokes = (Object[]) getVolumeList.invoke(storageManager, params);
	            if (invokes != null) {
	                StorageInfo info = null;
	                for (int i = 0; i < invokes.length; i++) {
	                    Object obj = invokes[i];
	                    Method getPath = obj.getClass().getMethod("getPath", new Class[0]);
	                    String path = (String) getPath.invoke(obj, new Object[0]);
	                    
	                    info = new StorageInfo(path);
	                    File file = new File(info.path);
	                    if ((file.exists()) && (file.isDirectory()) && (file.canWrite())) {
	                        Method isRemovable = obj.getClass().getMethod("isRemovable", new Class[0]);
	                        String state = null;
	                        try {
	                            Method getVolumeState = StorageManager.class.getMethod("getVolumeState", String.class);
	                            state = (String) getVolumeState.invoke(storageManager, info.path);
	                            info.state = state;
	                        } catch (Exception e) {
	                            e.printStackTrace();
	                        }

	                        if (info.isMounted()) {
	                            info.isRemoveable = ((Boolean) isRemovable.invoke(obj, new Object[0])).booleanValue();
	                            storages.add(info);
	                        }
	                    }
	                }
	            }
	        } catch (NoSuchMethodException e1) {
	            e1.printStackTrace();
	        } catch (IllegalArgumentException e) {
	            e.printStackTrace();
	        } catch (IllegalAccessException e) {
	            e.printStackTrace();
	        } catch (InvocationTargetException e) {
	            e.printStackTrace();
	        }
	        storages.trimToSize();

	        return storages;
	    }



   

(2)根据是否能移除的状态来判断,能够移除的是SD卡,不能移除的是机身存储。遍历(1)中返回的存储设备列表,可以很容易地获取到SD卡的路径和机身存储路径。

for (int i=0;i < count;i++) {
		item = storageList.get(i);
		if (item.isRemoveable) {
		<span >	</span>mSDCardPath += item.path + ";";
		} else {
		<span >	</span>mPhonePath +=  item.path + ";";
		}
	}




       最后,通过遍历存储设备列表,很容易知道是否存在SD卡;根据存储设备列表的size就可以知道一共挂载了多少存储设备。这里不再赘述。