如何获取Android文件管理器附件路径及转换content URI为真实文件路径
解决Android中Content Uri转真实文件路径的问题
我明白你遇到的困扰——从系统文件管理器选了Google Docs里的文件,拿到的是content://com.google.android.apps.docs.storage/document/acc=1;doc=6这种Uri,之前用MediaStore.Files.FileColumns.DATA查询的方法根本不管用,对吧?
这其实是因为两个核心原因:
- 从Android 10(API 29)开始,
DATA列已经被官方废弃,系统不再保证这个字段能返回有效的文件路径; - 像Google Drive这类第三方存储提供的Uri,对应的文件可能在云端或者应用沙盒里,根本没有“真实的设备本地路径”。
下面给你两种可行的解决方案,按需选择:
方案一:直接读取文件内容(推荐)
既然拿不到真实路径,不如直接通过ContentResolver打开文件输入流,直接把流上传到服务器——这是Android官方推荐的做法,适配所有高版本系统,也不需要额外的存储权限。
先获取文件名(用来给服务器识别文件):
import android.content.ContentResolver; import android.database.Cursor; import android.net.Uri; import android.provider.OpenableColumns; public String getFileName(Context context, Uri uri) { String fileName = null; Cursor cursor = context.getContentResolver().query( uri, new String[]{OpenableColumns.DISPLAY_NAME}, null, null, null ); if (cursor != null && cursor.moveToFirst()) { int nameIndex = cursor.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME); fileName = cursor.getString(nameIndex); cursor.close(); } return fileName; }
然后获取输入流上传:
// 上传时直接打开输入流 InputStream inputStream = getContentResolver().openInputStream(uri); // 把inputStream传给你的上传逻辑,比如用OkHttp: RequestBody requestBody = RequestBody.create(inputStream, MediaType.parse(getContentResolver().getType(uri))); MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", getFileName(this, uri), requestBody); // 后续执行上传请求...
方案二:复制文件到应用沙盒,获取临时路径
如果你的上传逻辑必须要文件路径(比如依赖旧的SDK),可以把Uri对应的文件复制到自己应用的私有沙盒目录,然后用这个临时路径:
import android.content.Context; import android.net.Uri; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; public String getTempFileAbsolutePath(Context context, Uri uri) throws IOException { String fileName = getFileName(context, uri); // 如果获取不到文件名,生成一个临时文件名 if (fileName == null) { fileName = "temp_upload_" + System.currentTimeMillis(); } // 应用私有目录,只有自己的应用能访问,不需要权限 File tempFile = new File(context.getFilesDir(), fileName); try (InputStream inputStream = context.getContentResolver().openInputStream(uri); FileOutputStream outputStream = new FileOutputStream(tempFile)) { byte[] buffer = new byte[1024 * 8]; int bytesRead; while ((bytesRead = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, bytesRead); } } return tempFile.getAbsolutePath(); }
使用时注意:这个临时文件用完记得删除,避免占用存储空间。
关键提醒
- 不需要申请
READ_EXTERNAL_STORAGE权限:通过文件选择Intent获取的Uri,系统已经赋予了你的应用临时访问权限,只要在获取Uri的Activity生命周期内使用即可;如果需要长期访问,可以调用getContentResolver().takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)。 - 不要纠结“真实路径”:对于第三方存储(比如Google Drive、OneDrive)的文件,本身就没有设备本地的真实路径,强行获取只会得到无效值。
内容的提问来源于stack exchange,提问作者stack Learner
相关产品推荐
相关产品推荐

