Android - 存储访问框架 - 将Uri转换为本地文件

3
我正在我的应用中使用存储访问框架(SAF)。为了扫描文件(照片或文档),我需要通过API发送本地文件路径。我已经成功设置了SAF,现在当用户选择文件时,我会得到一个Uri。
似乎Uri是云端的密钥,而不是本地文件。
Uri的值看起来像这样:
content://com.android.providers.media.documents/document/image:11862 

我该如何将这个Uri转换成本地文件?我需要从云端下载文件吗?怎么做呢?

2个回答

5
似乎Uri是云端的关键,而不是本地文件。 Uri是对内容的不透明引用。您无法知道数据在哪里,也不应该关心。
如何将此Uri转换为本地文件?
理想情况下,您不需要这样做。理想情况下,您可以使用支持InputStream的某个库“扫描文件(照片或文档)”。在这种情况下,您使用ContentResolveropenInputStream()获取流以传递给库。
如果您的库不支持InputStream作为数据源,则需要自己使用openInputStream(),使用Java I/O将内容复制为文件系统中的文件,以供您传递给库。

当一个库只接受文件或目录的绝对路径时怎么办? - masterwok
1
@masterwok:我会先向库的作者指出我五年前写的这篇博客文章,要求库的作者从流的角度思考,而不是文件。在他们改进API之前,您需要使用我答案中的InputStream将内容复制到您控制的文件中(例如,在getCacheDir()中)。然后,将该文件的路径传递给库。 - CommonsWare
谢谢您的快速回复。但是,我不确定我理解这对目录如何起作用。我使用的库有一个下载位置参数。然后它会将一个或多个文件下载到提供的位置。如果库的开发人员接受具有某些父位置的内容方案的Uri,那么他们是否可以使用ContentResolver和InputStream在该位置创建多个“文件”? - masterwok
1
如果库是针对Android特定的,并且您通过ACTION_OPEN_DOCUMENT_TREE获取了Uri,理论上它们可以在其中创建任何所需内容。 "tree" Uri是存储访问框架中目录的等效项,因此库可以使用DocumentFileContentResolver在该树内创建文档。或者,让库将内容下载到您控制的目录中,然后您可以担心将内容传输到文档树中。或者,跳过存储访问框架并坚持使用文件系统。 - CommonsWare
太棒了,我想我现在明白它是如何组合在一起的。谢谢! - masterwok

0

您可以在以下条件下直接从底层文件进行随机访问:

  • URI指向本地文件,您可以通过将URI权限与值com.android.externalstorage.documents进行比较来检查此项;
  • 您对URI具有读取和写入访问权限。
ParcelFileDescriptor parcelFileDescriptor = getContext().getContentResolver().openFileDescriptor(documentUri, "rw");
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
FileChannel channel = new FileInputStream(fileDescriptor).getChannel();

在保持FileChannel打开的同时,将FileDescriptor存储在某个地方:如果该对象被垃圾回收,则无法再访问文件。


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