Android:如何从媒体提供者URI获取文件路径与文件名?
解决content URI获取文件名时的
column '_data' does not exist错误 你遇到的这个错误很常见,原因主要有两点:
- 从Android 10(API 29)开始,
MediaStore.Audio.Media.DATA对应的_data列已经被官方废弃,系统不再保证这个列存在于媒体查询结果中; - 你使用的
content://com.android.providers.media.documents/document/audio%3A180是媒体文档提供者返回的URI,这类URI指向的是媒体库中的条目,而非直接的本地文件路径,所以直接查询_data必然会失败。
正确获取文件名的方法
下面给你两种可靠的实现方式:
方法1:查询通用的DISPLAY_NAME列
MediaStore.MediaColumns.DISPLAY_NAME是所有媒体类型(音频、图片、视频)都支持的列,直接返回文件的显示名称(也就是我们要的文件名):
Uri targetUri = Uri.parse("content://com.android.providers.media.documents/document/audio%3A180"); String fileName = null; // 只查询需要的列,提升性能 String[] projection = {MediaStore.MediaColumns.DISPLAY_NAME}; Cursor cursor = context.getContentResolver().query(targetUri, projection, null, null, null); if (cursor != null) { try { if (cursor.moveToFirst()) { int nameColumnIndex = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME); fileName = cursor.getString(nameColumnIndex); } } finally { cursor.close(); // 务必关闭Cursor,避免内存泄漏 } } // 此时fileName就是音频文件的名称
方法2:通过文档ID关联查询(适用于更复杂的场景)
如果需要同时获取更多媒体信息,可以通过文档ID拆分出媒体条目ID,再关联查询媒体库:
Uri targetUri = Uri.parse("content://com.android.providers.media.documents/document/audio%3A180"); String fileName = null; // 拆分文档ID,格式为"audio:180",分割后得到ID部分"180" String documentId = DocumentsContract.getDocumentId(targetUri); String[] splitId = documentId.split(":"); if (splitId.length == 2 && "audio".equals(splitId[0])) { String mediaId = splitId[1]; String[] projection = {MediaStore.Audio.Media.DISPLAY_NAME}; Cursor cursor = context.getContentResolver().query( MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection, MediaStore.Audio.Media._ID + "=?", new String[]{mediaId}, null ); if (cursor != null) { try { if (cursor.moveToFirst()) { fileName = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DISPLAY_NAME)); } } finally { cursor.close(); } } }
重要注意事项
- Scoped Storage限制:从Android 10开始,不要试图获取媒体文件的真实本地路径,系统通过Scoped Storage限制了直接文件系统访问,所有操作都应该通过
ContentResolver完成; - 权限申请:确保你的应用已经申请了对应的权限,Android 12及以下需要
READ_EXTERNAL_STORAGE,Android 13及以上可以申请更精细的READ_MEDIA_AUDIO权限; - Cursor关闭:所有查询得到的
Cursor必须在使用完毕后关闭,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Santhosh
相关产品推荐
相关产品推荐

