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

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

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;
    }

到此,该问题解决,项目也基本完成。 就写到这吧。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值