Android 11使用Intent.ACTION_OPEN_DOCUMENT选择Downloads文件夹PDF文件问题求助
问题原因
你遇到的路径仅返回数字标识的问题,本质是Android 4.4及以上版本的存储访问框架(SAF)通过ACTION_OPEN_DOCUMENT返回的是content://类型的共享Uri,而非传统的file://真实文件路径:
- 你自行创建的
fromPC文件夹若属于应用专属存储范围,系统会返回真实路径,因此读取正常 - Downloads属于公共存储目录,分区存储机制(Android 10+强制开启)不会向第三方应用暴露公共目录文件的真实路径,你拿到的末尾数字是MediaProvider的文件ID,并非路径片段
解决方案
1. 获取选中文件的正确文件名
在onActivityResult中通过ContentResolver查询Uri对应的文件信息即可拿到正确文件名,示例代码如下:
@Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode != Activity.RESULT_OK || data == null || requestCode != YOUR_REQUEST_CODE) { return; } Uri selectedPdfUri = data.getData(); if (selectedPdfUri == null) return; // 查询文件名 String fileName = null; Cursor cursor = getContentResolver().query(selectedPdfUri, null, null, null, null); if (cursor != null && cursor.moveToFirst()) { fileName = cursor.getString(cursor.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME)); cursor.close(); } // 此时fileName即为正确的文件名,比如PaymentNotification.pdf }
2. 获取可操作的java.io.File对象
分区存储下你无法直接获取公共目录文件的File对象,通用解决方案是将Uri对应的文件内容拷贝到你的应用专属缓存目录/文件目录,即可得到正常的File对象:
// 把Uri对应文件拷贝到应用缓存目录,返回File对象 private File copyUriToCacheFile(Context context, Uri uri, String fileName) throws IOException { File cacheFile = new File(context.getCacheDir(), fileName); InputStream inputStream = context.getContentResolver().openInputStream(uri); FileOutputStream outputStream = new FileOutputStream(cacheFile); byte[] buffer = new byte[4096]; int len; while ((len = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, len); } inputStream.close(); outputStream.close(); return cacheFile; }
调用上述方法拿到的cacheFile即可正常进行读写操作。
3. 无需File对象的轻量读取方案
如果你只是需要读取PDF内容,不需要持有File对象,可以直接通过ContentResolver打开输入流操作,无需拷贝文件:
InputStream pdfInputStream = getContentResolver().openInputStream(selectedPdfUri); // 直接将输入流传给PDF解析组件即可
注意事项
- 禁止手动解析
content://格式的Uri字符串拼接路径,不同厂商、不同系统版本的Uri格式不统一,该做法兼容性极差 - 如果你需要长期访问选中的文件,在拿到Uri后需要申请长期访问权限,避免应用重启后无法再读取该Uri:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { getContentResolver().takePersistableUriPermission(selectedPdfUri, Intent.FLAG_GRANT_READ_URI_PERMISSION); }
内容的提问来源于stack exchange,提问作者Jethro Gibbs
相关产品推荐
相关产品推荐

