您的位置:首页 > 移动开发 > Android开发

Android手机内置SD卡路径的获取

2016-01-19 16:07 513 查看
最近,在做一个照相机相关的应用,项目都已经收尾了,静待领导检阅。 但领导一运行,应用马上蹦了, 我的命呀,倒霉! 但这就是程序猿的命~~
原来就只有一台样机出现了问题,深究是关于文件存储的问题。下面就一步一步来说明我的解决过程。


1。出现的问题及现象

1)出现问题的样机:ZTE U930HD(内置存储卡2G,没有插入外置SD卡)

其他样机都没有问题。

2)现象:拍照后的照片无法存储

相关的log如下:

01-19 15:20:25.625: W/System.err(21600): java.io.FileNotFoundException: /mnt/sdcard/MMCamera/photo/20160119152025.jpg: open failed: EACCES (Permission denied)
01-19 15:20:25.625: W/System.err(21600):    at libcore.io.IoBridge.open(IoBridge.java:406)
01-19 15:20:25.625: W/System.err(21600):    at java.io.FileOutputStream.<init>(FileOutputStream.java:88)
01-19 15:20:25.625: W/System.err(21600):    at java.io.FileOutputStream.<init>(FileOutputStream.java:73)
01-19 15:20:25.625: W/System.err(21600):    at com.wuxianxi.mmcamera.utils.FileUtil.saveImageToSDCard(FileUtil.java:26)
01-19 15:20:25.625: W/System.err(21600):    at com.wuxianxi.mmcamera.view.MainActivity$2.onPictureTaken(MainActivity.java:310)
01-19 15:20:25.625: W/System.err(21600):    at android.hardware.Camera$EventHandler.handleMessage(Camera.java:754)
01-19 15:20:25.625: W/System.err(21600):    at android.os.Handler.dispatchMessage(Handler.java:99)
01-19 15:20:25.625: W/System.err(21600):    at android.os.Looper.loop(Looper.java:137)
01-19 15:20:25.625: W/System.err(21600):    at android.app.ActivityThread.main(ActivityThread.java:4424)
01-19 15:20:25.625: W/System.err(21600):    at java.lang.reflect.Method.invokeNative(Native Method)
01-19 15:20:25.625: W/System.err(21600):    at java.lang.reflect.Method.invoke(Method.java:511)
01-19 15:20:25.625: W/System.err(21600):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
01-19 15:20:25.625: W/System.err(21600):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
01-19 15:20:25.625: W/System.err(21600):    at dalvik.system.NativeStart.main(Native Method)
01-19 15:20:25.625: W/System.err(21600): Caused by: libcore.io.ErrnoException: open failed: EACCES (Permission denied)
01-19 15:20:25.625: W/System.err(21600):    at libcore.io.Posix.open(Native Method)
01-19 15:20:25.625: W/System.err(21600):    at libcore.io.BlockGuardOs.open(BlockGuardOs.java:110)
01-19 15:20:25.625: W/System.err(21600):    at libcore.io.IoBridge.open(IoBridge.java:390)
01-19 15:20:25.635: W/System.err(21600):    ... 13 more


2。分析原因

1)手机连接Eclipse,查看DDMS ->File Explorer,看到内置存储的挂载目录是:/mnt/sdcard2

但我应用中获取存储路径的代码Environment.getExternalStorageDirectory(),返回:“/mnt/sdcard”

原来获取存储路径错误, 再进一步确认一下

Environment.getExternalStorageState(),却返回 ”removed“;

原来用Environment.getExternalStorageDirectory()获得的是外置存储卡,但因没有插入外置SD卡,所以不能存储。

2)那为什么其他的样机没有问题呢?

不同的样机上,调用getExternalStorageDirectory()返回值却不一样。查询了Android的文档,才找到原因,原来这个方法返回的是当前设备厂商所认为的“外部存储”,有可能返回外置的SD卡目录(Micro SD Card),也可能返回内置的SD卡目录(eMMC)。

大部分样机,将eMMC存储挂载在Environment.getExternalStorageDirectory()这个节点,而将真正的外置SD卡挂载到/mnt/external_sd、/mnt/sdcard2 等节点。

但也有一小部分,像现在的中兴ZTE U930HD刚好相反,将eMMC存储挂载到 /mnt/external_sd 、/mnt/sdcard2 等节点,而将外置的SD卡挂载到 Environment.getExternalStorageDirectory()这个结点。

3。解决办法

像上面说的,如果使用 Environment.getExternalStorageDirectory() 获取到的是外置SD卡路径,但又没有插入外置SD卡,这个时候要用内置的eMMC存储来存储一些程序中用到的数据,应该怎样获取这个eMMC存储的路径呢?

网上找了一些资料,觉得比较好的是,通过扫描系统文件”system/etc/vold.fstab”来实现。“system/etc/vold.fstab” 只是一个简单的配置文件,它描述了Android的挂载点信息。

先通过遍历该配置文件,获取所有的挂载点:

//获取android所有的挂载点
private static List<String> getDevMountList() {
List<String> mVold = new ArrayList<String>(10);
mVold.add("/mnt/sdcard");

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];
Log.d(TAG, "Vold: element = "+element);

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

return mVold;
}


然后,判断Environment.getExternalStorageState()的值,如果返回的是Environment.MEDIA_MOUNTED(“mounted”)说明获取的是内置SD卡路径,能够正确存储;否则,说返回的是外置SD卡,那么就要从上面所有挂载点中找一个能够存储的路径,进行存储操作。参考代码:

public static String getExternalSdCardPath() {
String  path = null;
String state = Environment.getExternalStorageState();
//Environment.getExternalStorageDirectory()获取的是内部SDcard
if (Environment.MEDIA_MOUNTED.equals(state)) {
path = Environment.getExternalStorageDirectory().getPath();
} else {  //Environment.getExternalStorageDirectory()获取的是外部SDcard,但没插外部sdcard
List<String> devMountList = getDevMountList();
for (String devMount : devMountList) {
File file = new File(devMount);
if (file.isDirectory() && file.canWrite()) {
path = file.getAbsolutePath();
break;
}
}
}
Log.d(TAG, "getExternalSdCardPath: path = "+path);
return path;
}


到此,该问题解决,项目也基本完成。 就写到这吧。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: