如何使用ACTION_OPEN_DOCUMENT_TREE意图获取真实路径?

21

我的应用程序会下载并解压缩文件到特定文件夹:

output = new FileOutputStream(realpath, true);
output.write(buffer, 0, bytesRead);

ZipFile zipFile = new ZipFile(realpath);

有了新引入的 ACTION_OPEN_DOCUMENT_TREE 意图,我想为用户提供选择该文件夹的选项。

在测试我的 onActivityResult 中接收到的值时,我得到了类似于 /tree/primary:mynewfolder 的路径,它并不是实际物理路径,如 /sdcard/mynewfolder

Uri treeUri = data.getData();
String sPath = treeUri.getPath();
Log.v("Path from Tree ", sPath);

我的解压方法需要真实路径:

ZipFile zipFile = new ZipFile(realpath);

我如何从Lollipop(API 21和22)提供的URI获取真实路径,例如/sdcard/mynewfolder


你能演示一下如何使用ACTION_OPEN_DOCUMENT_TREE让用户选择文件夹吗? - eri0o
3个回答

32

从URI中获取实际路径的过程与以前相同,但需要稍作修改:

Uri uri = data.getData();
Uri docUri = DocumentsContract.buildDocumentUriUsingTree(uri, 
                        DocumentsContract.getTreeDocumentId(uri));
String path = getPath(this, docUri);

可以在这里找到getPath()方法与中间方法的要点:getPath()


4
关于SD卡路径似乎不起作用。你是怎么做的?对我来说,它会崩溃,因为它返回了空值(尽管它确定它是外部存储类型)。 - android developer
2
@androiddeveloper 你找到外部SD卡的解决方案了吗?我也遇到了类似的问题。无法获取所选文件夹在外部SD卡中的真实路径。 - TOP
@Sunshinetpu 我找到了一种方法,但这只是一个解决办法。在您的应用程序外部存储路径上创建一个唯一的文件,并尝试通过DocumentFile找到它。如果找到了它,那么它就是相同的外部存储路径,您可以使用与外部存储相同的路径。 - android developer
2
@CoolGuy 哦。也许这个链接可以帮到你:https://www.programcreek.com/java-api-examples/index.php?source_dir=Augendiagnose-master/AugendiagnoseIdea/augendiagnoseLib/src/main/java/de/jeisfeld/augendiagnoselib/util/imagefile/FileUtil.java 或者这个链接:https://dev59.com/jlsW5IYBdhLWcg3wfXNa#36162691 。搜索 getFullPathFromTreeUri。将其设置为公共的并尝试使用。如果它有效,请在此处发布答案。我不能测试它,因为我没有SD卡。 - android developer
1
@androiddeveloper 非常感谢!匿名用户的回答很有用!那正是我想要的。 - Spikatrix
显示剩余12条评论

1
显然,为了评论或编辑Minute V的答案,我需要声望。因为我猜对于那些不想要外部库或具有向后兼容性的人来说,它仍然是相关的。
从Uri中获取的路径应该相对于Environment.getExternalStorageDirectory().getPath()。据我所知,它将有一些“:”以分隔链接上的信息。
您只需拆分链接并获取数组中的最后一个值即可获得相对路径。然后,您只需使用Environment.getExternalStorageDirectory().getPath()并添加“/”,然后再添加您的路径。
这是我使用的代码:
            Uri uri = resultData.getData();
            String [] pathsections = resultData.getData().getPath().split(":");
            path  = Environment.getExternalStorageDirectory().getPath() + "/" + pathsections[pathsections.length-1];

正如您所看到的,不需要进行所有的if判断,Environment.getExternalStorageDirectory().getPath()可以获取物理设备上的路径,因此您不必费心硬编码路径。


0
无需检查 Android 版本..
public static string GetRealPath(DocumentFile treeUri)
        {
            if (treeUri == null)
                return "";
            var path1 = treeUri.Uri.Path;
            if (path1.StartsWith("/tree/"))
            {
                var path2 = path1.Remove(0, "/tree/".Length);
                if (path2.StartsWith("primary:"))
                {
                    var primary = path2.Remove(0, "primary:".Length);
                    if (primary.Contains(':'))
                    {
                        
                        var storeName = "/storage/emulated/0/";
                        var last = path2.Split(':').LastOrDefault();
                        var realPath = storeName + last;
                        return realPath;
                    }
                }
                else
                {
                    if (path2.Contains(':'))
                    {
                        var path3 = path2.Split(':').FirstOrDefault();
                        var storeName = path3;
                        var last = path2.Split(':').LastOrDefault();
                        var realPath = "/" + storeName + "/" + last;
                        return realPath;
                    }
                }
            }
            return path1;
        }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接