我知道我们可以正常从内部存储打开文件,如下所示:
File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath(), "my_file.zip");
Uri uri = (FileProvider.getUriForFile(context, AUTHORITY_OPEN_FILE, file)
Intent intent = new Intent(Intent.ACTION_VIEW)
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.setData(uri);
context.startActivity(intent);
但我不知道如何从SD卡打开文件,我们可以使用DocumentFile
这样选择:
Uri uri = new Uri.Builder()
.scheme("content")
.authority("com.android.externalstorage.documents")
.appendPath("document")
.appendPath(directory)
.appendPath(fileName)
.build();
DocumentFile documentFile = DocumentFile.fromSingleUri(context, uri);
我尝试了以下代码段:
Uri uri = documentFile.getUri();
Intent intent = new Intent(Intent.ACTION_VIEW)
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.setData(uri);
context.startActivity(intent);
但结果是错误:
Caused by: java.lang.SecurityException: Permission Denial: starting Intent { act=android.intent.action.VIEW dat=content://com.android.externalstorage.documents/document/6331-6132:/haxm-windows_r05_2.zip flg=0x10000001 cmp=com.google.android.gm/.browse.TrampolineActivity } from ProcessRecord{a0ed6d5 9894:com.mypackage.app/u0a169} (pid=9894, uid=10169) requires com.google.android.gm.permission.READ_GMAIL
我确实授予了读写外部存储权限:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
还有Uri
权限:
int takeFlags = data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
context.getContentResolver().takePersistableUriPermission(uri, takeFlags);
存储在SD卡中的文件为我们提供Uri
,6331-6132
是我们可移动SD卡的标识符:
content://com.android.externalstorage.documents/document/6331-6132:Folder/haxm-windows_r05_2.zip
我在StackOverflow上阅读了很多帖子,但没有任何帮助。你能帮我解决这个错误吗?提前谢谢。
答案 0 :(得分:0)
这可能是非常基本的,但错误消息表明您缺少权限
你问READ_EXTERNAL_STORAGE
了吗?
https://developer.android.com/training/data-storage/files#ExternalStoragePermissions
答案 1 :(得分:0)
你必须在清单文件中添加权限,对于marshmallow或以上版本的android你添加运行时权限。 对于这个观点
https://www.simplifiedcoding.net/android-marshmallow-permissions-example/
答案 2 :(得分:0)
我使用Intent.ACTION_OPEN_DOCUMENT获取Uri。接下来,我将Uri保存到我的数据库中。最后,我使用getContentResolver()。openInputStream(uri)重建Uri来获取流。
我的猜测是,在将ContentResolver
保存到数据库之前,您没有在onActivityResult()
中的Uri
上调用test.route
。没有这个,you do not have long-term access to the content identified by the Uri
。
答案 3 :(得分:0)
我终于找到了解决方案。使用java.lang.SecurityException: Permission Denial
打开外部文件时,将引发DocumentFile.fromSingleUri(context, uri)
。只有当您使用操作onActivityResult()
或Intent.ACTION_OPEN_DOCUMENT
在Intent.ACTION_CREATE_DOCUMENT
方法中选择文件时,此静态方法才有用。当您的应用被销毁时,访问该文件的权限就会消失。在处理需要很长时间权限的文件时,不应使用DocumentFile.fromSingleUri(context, uri)
。因此,我们需要DocumentFile.fromTreeUri(context, uri)
。
为此,您必须首先访问SD卡ID的根目录(例如6331-6132
)。例如:
String path = "6331-6132:Video/Iykwim.mp4";
String sdcardId = path.substring(0, path.indexOf(':') + 1); // => returns '6331-6132:'
Uri uri = Uri.parse("content://com.android.externalstorage.documents/tree/" + Uri.encode(sdcardId));
DocumentFile root = DocumentFile.fromTreeUri(context, uri);
// Now, we already have the root of SD card.
// Next, we will get into => Video => Iykwim.mp4
DocumentFile file = root.findFile("Video").findFile("Iykwim.mp4");
请注意,无法直接访问该文件,例如Uri
:
String path = "6331-6132:Video/Iykwim.mp4";
Uri uri = Uri.parse("content://com.android.externalstorage.documents/tree/" + Uri.encode(path));
DocumentFile file = DocumentFile.fromTreeUri(context, uri);
或者像这样:
String folder = "6331-6132:Video";
Uri uri = Uri.parse("content://com.android.externalstorage.documents/tree/" + Uri.encode(folder));
DocumentFile directoryVideo = DocumentFile.fromTreeUri(context, uri);
DocumentFile file = directoryVideo.findFile("Iykwim.mp4");
最后,您可以使用Intent.ACTION_VIEW
打开文件:
Intent intent = new Intent(Intent.ACTION_VIEW)
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.setData(documentFile.getUri());
context.startActivity(intent);
最糟糕的情况是当你从里面有这么多文件的文件夹中调用findFile()
时。这将需要很长时间,并可能导致您的应用程序崩溃。确保始终从不同的线程调用此方法。
Android日益恶化。他们制作了一个存储访问框架(SAF),使您难以管理SD卡上的文件。自Android Kitkat以来,使用java.io.File
几乎已被弃用。您应该使用DocumentFile
代替。