Android4.4之后的外置SD卡文件读写的解决方法

在Android4.4之后,普通应用就没有外置SD卡的写权限了,对于要操作外置SD的应用来说就是个灾难了。

我最近做一个文件管理器,发现外卡只有读权限,没有办法进行其他操作,刚开始以为是需要运行时权限,然后进队权限进行申请,发现还是不行,然后继续百度Google基本上都是和权限有关,无意发现有一篇是写授权的,根据文章思路,对比了ES文件浏览器。确实在写外置SD卡文件时会弹出这样一个界面:Android4.4之后的外置SD卡文件读写的解决方法_第1张图片

点击选择进入系统的一个文件目录界面:Android4.4之后的外置SD卡文件读写的解决方法_第2张图片

点击“选择SD"卡,回来就可以对文件进行操作了。

大概思路就是,先去获取对sdcard进行授权

Intent intent  = new Intent("android.intent.action.OPEN_DOCUMENT_TREE");

this.startActivityForResult(intent, requestCode);

过程如上图,点击左边sdcard,在点击右下角的选择,然后在onActivityResult中接收返回结果,如果没有选择sdcard则进行提示在此获取授权,如果获取授权成功,就保存treeUri,就是外置SD的文档Uri。这个Uri和普通Uri是不一样的,打印出来是这样的:

 content://com.android.externalstorage.documents/tree/6635-3265%3A中间有个tree。这个uri可以保存起来,可以避免每一次操作都去获取这个uri

再去找文件操作时是怎么样的,发现外置SD卡都是通过DocumentFile进行文件写的。先根据之前保存的SD卡uri获取根DocumentFile,在一层一层获取子DocumentFile。

@Override  
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
        switch (requestCode) {  
            case requestCode:  
                if (resultCode == RESULT_OK) {
                    Uri treeUri = data.getData();
                    if (!":".equals(treeUri.getPath().substring(treeUri.getPath().length() - 1)) || treeUri.getPath().contains("primary")) {  
                        Toast.makeText(this, "没有选择SDCARD!", Toast.LENGTH_LONG).show();
                    } else {  
                        DocumentFile document = DocumentFile.fromTreeUri(this, treeUri);
                        String[] parts = getStoragePath() +"/test.txt".split(File.separator);  
                        for (int i = 3; i < parts.length; i++) {  
                            DocumentFile nextDocument = document.findFile(parts[i]);  
                            if (nextDocument == null) {  
                                if (i < parts.length - 1) {  
                                    if (true) {  
                                        nextDocument = document.createDirectory(parts[i]); 
                                    }  
                                } else {  
                                    nextDocument = document.createFile("test.txt", parts[i]);  
                                }  
                            }  
                            document = nextDocument;  
                        } 
                    }  
                }  
        } 
        super.onActivityResult(requestCode, resultCode, data);  
    }

获取sdcard路径

public String getStoragePath() {
        String resultpath = "";
        StorageManager mStorageManager = (StorageManager) getSystemService(Context.STORAGE_SERVICE);
        Class storageVolumeClazz = null;
        try {
            storageVolumeClazz = Class
                    .forName("android.os.storage.StorageVolume");

            Method getVolumeList = mStorageManager.getClass().getMethod(
                    "getVolumeList");

            Method getPath = storageVolumeClazz.getMethod("getPath");

            Object result = getVolumeList.invoke(mStorageManager);

            final int length = Array.getLength(result);

            Method getUserLabel = storageVolumeClazz.getMethod("getUserLabel");

            for (int i = 0; i < length; i++) {

                Object storageVolumeElement = Array.get(result, i);

                String userLabel = (String) getUserLabel
                        .invoke(storageVolumeElement);
                String path = (String) getPath.invoke(storageVolumeElement);

                if (userLabel.contains("SD")) {
                    resultpath = path;
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return resultpath;
    }

path是要获取文件的路径,createDirectories是是否要新建,false用于获取DocumentFile执行删除操作,true用于新建文件。遍历不从0开始是因为path的是绝对路径,前面SD卡的路径不需要,从SD卡的第一层目录开始遍历。

有了思路就可以更好的找方法了,再在google搜DocumentFile,SD卡相关的,在stackOverFlow找到了这个:

http://stackoverflow.com/questions/26744842/how-to-use-the-new-sd-card-access-api-presented-for-lollipop

下来就实现你想要的东西了,不过还有许多细节性的东西需要注意!

你可能感兴趣的:(android)