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; }
到此,该问题解决,项目也基本完成。 就写到这吧。
相关文章推荐
- Android 5.0新增任务调度作业jobScheduler
- Android studio 史上最简单添加so库
- Android图片加载神器之Fresco-加载图片基础[详细图解Fresco的使用]
- Android-MediaRecord介绍
- Android拨号程序的编写
- Android——点击复制TextView中部分特殊样式字体
- 关于android native层的Ixxx 接口中Binder机制的探讨
- Android开发之控制相机
- Android开发出现ScrollView can host only one direct child
- 2015最流行的Android组件、工具、框架大全
- Android中SQLite使用
- android自定义底部Tab,项目整体界面框架
- Android高效压缩图片不失真的方法总结
- Android 通过 Intent 传递类对象
- 史上最详细的Android Studio系列教程(六)--Gradle多渠道打包
- 史上最详细的Android Studio系列教程(五)--Gradle命令详解与导入第三方包
- 使用Android Studio开发ndk-Jni(入门)
- Android使用Activity用作弹出式对话框
- 史上最详细的Android Studio系列教程(四)--Gradle基础
- 史上最详细的Android Studio系列教程(三)--快捷键