Android中如何从Content Uri获取File格式的文件路径?
从Content Uri获取本地
file://路径的解决办法 你当前代码里直接拿uri.getPath()创建File是错误的——content://开头的Uri是Android内容提供者的统一标识,它的getPath()部分并非真实的本地文件路径,自然无法转换成file://格式。下面给你两种可行的解决思路:
方法一:解析Content Uri到真实外部存储路径(限可公开访问的文件)
如果文件在外部存储且能被系统媒体库索引,可以通过ContentResolver结合DocumentsContract解析出真实路径:
先添加工具方法:
public String getRealPathFromContentUri(Context context, Uri uri) { String filePath = null; // 处理DocumentProvider类型的Uri if (DocumentsContract.isDocumentUri(context, uri)) { // 外部存储文档 if ("com.android.externalstorage.documents".equals(uri.getAuthority())) { final String docId = DocumentsContract.getDocumentId(uri); final String[] split = docId.split(":"); if ("primary".equalsIgnoreCase(split[0])) { filePath = Environment.getExternalStorageDirectory() + "/" + split[1]; } } // 下载目录文档 else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())) { final String id = DocumentsContract.getDocumentId(uri); final Uri contentUri = ContentUris.withAppendedId( Uri.parse("content://downloads/public_downloads"), Long.parseLong(id)); filePath = getDataColumn(context, contentUri, null, null); } // 媒体文件(图片/视频/音频) else if ("com.android.providers.media.documents".equals(uri.getAuthority())) { final String docId = DocumentsContract.getDocumentId(uri); final String[] split = docId.split(":"); final String type = split[0]; Uri contentUri = null; switch (type) { case "image": contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; break; case "video": contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; break; case "audio": contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; break; } filePath = getDataColumn(context, contentUri, "_id=?", new String[]{split[1]}); } } // 普通content:// Uri else if ("content".equalsIgnoreCase(uri.getScheme())) { filePath = getDataColumn(context, uri, null, null); } // 已经是file:// Uri的情况 else if ("file".equalsIgnoreCase(uri.getScheme())) { filePath = uri.getPath(); } return filePath; } // 从ContentResolver查询_data列获取路径 private String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) { Cursor cursor = null; final String[] projection = {"_data"}; try { cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null); if (cursor != null && cursor.moveToFirst()) { int columnIndex = cursor.getColumnIndexOrThrow("_data"); return cursor.getString(columnIndex); } } finally { if (cursor != null) cursor.close(); } return null; }
然后修改你的viewPdf方法:
private void viewPdf(Intent getPdf, String action) { Uri uri = getPdf.getData(); // 直接用getData(),无需重复parse if (uri != null) { String realPath = getRealPathFromContentUri(this, uri); if (realPath != null) { String fileSchemePath = "file://" + realPath; name = new File(realPath).getName(); path = fileSchemePath; Log.d("sdsfgsdfsdf", "拿到的file路径:" + fileSchemePath); } else { // 解析失败,切换到缓存方案 String cachedPath = copyToCache(this, uri); if (cachedPath != null) { path = "file://" + cachedPath; Log.d("sdsfgsdfsdf", "缓存后的file路径:" + path); } } } }
方法二:复制文件到应用缓存(通用所有情况)
如果文件是其他应用的私有文件,或者解析真实路径失败,可将Content Uri对应的文件复制到自己应用的缓存目录,再使用缓存文件的路径:
private String copyToCache(Context context, Uri uri) { try { InputStream input = context.getContentResolver().openInputStream(uri); if (input == null) return null; File cacheDir = context.getCacheDir(); File tempPdf = new File(cacheDir, "temp_pdf_" + System.currentTimeMillis() + ".pdf"); OutputStream output = new FileOutputStream(tempPdf); byte[] buffer = new byte[1024]; int len; while ((len = input.read(buffer)) != -1) { output.write(buffer, 0, len); } input.close(); output.close(); return tempPdf.getAbsolutePath(); } catch (IOException e) { e.printStackTrace(); return null; } }
重要提醒
- Android 10及以上版本,直接访问外部存储需要
MANAGE_EXTERNAL_STORAGE权限,否则方法一可能失效,建议优先使用ContentResolver操作文件,而非强行转换真实路径。 - 缓存文件使用完毕后记得删除,避免占用应用缓存空间。
内容的提问来源于stack exchange,提问作者Anushka
相关产品推荐
相关产品推荐

