Android中的Environment.getExternalStorageState使用,对内置外置SD卡的判断

如果我们想要读取或者向SD卡写入,这时就必须先要判断一个SD卡的状态,否则有可能出错。

先解释一下挂载:这是linux系统的术语,就是加载的意思,把sd卡划入系统相连,让系统能认到并读取sd卡的内容

<span style="font-family: Arial; line-height: 26px;">那么SD卡状态为什么时才能读取呢,经过我的各种情况的实践,大致如下:</span>

SD状态
现象描述
/mnt/sdcard目录是否存在
canRead返回
canWrite返回
在/mnt/sdcard创建文件
在/mnt/sdcard创建文件夹
MEDIA_MOUNTED
SD卡正常挂载
TRUE
TRUE
TRUE
TRUE
TRUE
MEDIA_REMOVED
无介质
TRUE
FALSE
FALSE
false:  原因Permission denied
FALSE
MEDIA_UNMOUNTED
有介质,未挂载,在系统中删除
TRUE
FALSE
FALSE
false:  原因Permission denied
FALSE
MEDIA_BAD_REMOVAL
介质在挂载前被移除,直接取出SD卡
TRUE
FALSE
FALSE
false:  原因Permission denied
FALSE
MEDIA_CHECKING
正在磁盘检查,刚装上SD卡时
TRUE
FALSE
FALSE
false:  原因Permission denied
FALSE
MEDIA_SHARED
SD卡存在但没有挂载,并且通过USB大容量存储共享,操作打开USB存储
TRUE
FALSE
FALSE
false:  原因Permission denied
FALSE
MEDIA_MOUNTED_READ_ONLY
sd卡存在并且已挂载,但是挂载方式为只读
-
-
无法模拟,SD卡不允许修改权限
MEDIA_NOFS
介质存在但是为空白或用在不支持的文件系统
-
-
无法模拟,SD卡格式化后再加载会自动生成系统文件
MEDIA_UNMOUNTABLE
存在SD卡但是不能挂载,例如发生在介质损坏
-
-
无法模拟

通过上表可以看出,只有在SD卡状态为MEDIA_MOUNTED时/mnt/sdcard目录才是可读可写,并且可以创建目录及文件。
所以我们读取SD卡时一般会这么写:
?
 
01
02
03
04
05
06
String state;
String path;
state = Environment.getExternalStorageState();
if(state.equals(Environment.MEDIA_MOUNTED)){
path = Environment.getExternalStorageDirectory().getAbsolutePath();


读写SD卡记得加这两个权限:

?

 

01

02

<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>

   <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

 

1 在AndroidManifest文件中加入sdcard操作权限
  * <!--在SDCard中创建与删除文件权限 -->
  * <uses-permissioandroid:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> 
  * <!--往SDCard写入数据权限 --> 
  * <uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 
* 2 确认sdcard的存在
  * android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)
* 3 获取扩展存储设备的文件目录
  * android.os.Environment.getExternalStorageDirectory();

 

/////////////////////////////////////////////////

http://www.vogella.com/articles/Android/article.html#resources_android

http://www.coreservlets.com/android-tutorial/

===================================================================================================================

Android 获取外置SD卡(TF卡)的问题

Android手机上的外置SD卡,起初的时候,即在Android出世的前几年,那时手机的存储是十分有限的,不像现在到处可见16G、32G和64G的存储,因而那时候的手机有的厂商允许插入外置的SD卡,此时这张卡仍处于手机的扩展部分。后来,随着手机的发展以及存储能力的增加,这张外置SD卡,逐渐成为了手机的一部分,不再允许可插拔了,当然现在依然有的手机允许对存储进行拓展,比如三星等。

那张拓展的存储卡,现在叫做TF卡,且不是所有的手机都支持它,但是有时候有些奇葩需求偏要优先存储在TF卡里面,这叫不得不要求开发人员去检查这张卡是否存在、是否可用。又因为这是手机厂商可拓展、可自定义的部分,所有不同厂商生产的手机,以及同一厂商生产的不同型号的手机,TF卡的位置都相差很大,并没有一个统一的名称或位置。因而这是比较困难的一部分,但是还好Android是开源的,我们可以通过运行时来判断手机是否有TF卡,以及TF卡是否可用。

下面这个方法可以获取手机的可以存储,包括SD卡、TF卡等,对多存储卡进行了匹配,详细的代码如下:

复制代码
 1 public class SDCardScanner {
 2     /*
 3      * avoid initializations of tool classes
 4      */
 5     private SDCardScanner() {
 6     }
 7 
 8     /**
 9      * @Title: getExtSDCardPaths
10      * @Description: to obtain storage paths, the first path is theoretically
11      *               the returned value of
12      *               Environment.getExternalStorageDirectory(), namely the
13      *               primary external storage. It can be the storage of internal
14      *               device, or that of external sdcard. If paths.size() >1,
15      *               basically, the current device contains two type of storage:
16      *               one is the storage of the device itself, one is that of
17      *               external sdcard. Additionally, the paths is directory.
18      * @return List<String>
19      * @throws IOException
20      */
21     public static List<String> getExtSDCardPaths() {
22         List<String> paths = new ArrayList<String>();
23         String extFileStatus = Environment.getExternalStorageState();
24         File extFile = Environment.getExternalStorageDirectory();
25         if (extFileStatus.equals(Environment.MEDIA_MOUNTED)
26                 && extFile.exists() && extFile.isDirectory()
27                 && extFile.canWrite()) {
28             paths.add(extFile.getAbsolutePath());
29         }
30         try {
31             // obtain executed result of command line code of 'mount', to judge
32             // whether tfCard exists by the result
33             Runtime runtime = Runtime.getRuntime();
34             Process process = runtime.exec("mount");
35             InputStream is = process.getInputStream();
36             InputStreamReader isr = new InputStreamReader(is);
37             BufferedReader br = new BufferedReader(isr);
38             String line = null;
39             int mountPathIndex = 1;
40             while ((line = br.readLine()) != null) {
41                 // format of sdcard file system: vfat/fuse
42                 if ((!line.contains("fat") && !line.contains("fuse") && !line
43                         .contains("storage"))
44                         || line.contains("secure")
45                         || line.contains("asec")
46                         || line.contains("firmware")
47                         || line.contains("shell")
48                         || line.contains("obb")
49                         || line.contains("legacy") || line.contains("data")) {
50                     continue;
51                 }
52                 String[] parts = line.split(" ");
53                 int length = parts.length;
54                 if (mountPathIndex >= length) {
55                     continue;
56                 }
57                 String mountPath = parts[mountPathIndex];
58                 if (!mountPath.contains("/") || mountPath.contains("data")
59                         || mountPath.contains("Data")) {
60                     continue;
61                 }
62                 File mountRoot = new File(mountPath);
63                 if (!mountRoot.exists() || !mountRoot.isDirectory()
64                         || !mountRoot.canWrite()) {
65                     continue;
66                 }
67                 boolean equalsToPrimarySD = mountPath.equals(extFile
68                         .getAbsolutePath());
69                 if (equalsToPrimarySD) {
70                     continue;
71                 }
72                 paths.add(mountPath);
73             }
74         } catch (IOException e) {
75             // TODO Auto-generated catch block
76             e.printStackTrace();
77         }
78         return paths;
79     }
80 }
复制代码

首先,我把它写成了一个工具类,因而声明了一个私有的构造器,目的就是要防止该类被实例化。

然后,首先获取了Android标准一部分的外置SD卡,如果它可用的话。

然后利用运行时,通过命令行函数"mount"来获取所有的存储位置,并对返回的结果进行SD卡或者TF卡的查找。

最后返回了所有可用于存储的不同的卡的位置,用一个List来保存。由于不是所有的手机都支持TF卡,因而这个List包含的路径未必很多,只有一个SD卡的手机只会返回一个路径,多个可用存储位置的会返回多个路径。

但有一点,是必须的,paths.get(0)肯定是外置SD卡的位置,因为它是primary external storage.

Shit happens, but life goes on.


你可能感兴趣的:(android,读取,判断,内置外置sd卡)