Android Studio中能否通过Cursor提取单个音视频文件元数据?
用Cursor提取单个音视频文件元数据的方法
当然可以通过Cursor搭配MediaStore提取单个音视频文件的元数据,这种方式比遍历全部媒体文件效率更高,核心是通过目标文件的Content URI精准查询对应的媒体表。下面是具体实现步骤:
一、权限准备
- Android 13及以上:需要申请
READ_MEDIA_AUDIO(音频)或READ_MEDIA_VIDEO(视频)权限 - Android 12及以下:需要申请
READ_EXTERNAL_STORAGE权限
注意:所有权限都需要动态申请,确保用户授权后再执行查询操作。
二、获取目标文件的Content URI
如果是通过系统文件选择器获取的文件,能直接拿到对应的Content URI;如果仅知道文件路径,Android 10及以上推荐通过MediaStore查询匹配的URI,避免Scoped Storage限制,示例代码如下:
fun getUriFromFilePath(context: Context, filePath: String): Uri? { val projection = arrayOf(MediaStore.Audio.Media._ID) val selection = "${MediaStore.Audio.Media.DATA} = ?" val selectionArgs = arrayOf(filePath) context.contentResolver.query( MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection, selection, selectionArgs, null )?.use { cursor -> if (cursor.moveToFirst()) { val id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID)) return ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id) } } return null }
(视频文件只需把MediaStore.Audio替换为MediaStore.Video即可)
三、查询并解析元数据
拿到目标文件的Content URI后,就可以通过ContentResolver.query()获取Cursor,进而提取元数据。
音频文件示例
fun getSingleAudioMeta(context: Context, audioUri: Uri) { // 定义需要提取的元数据字段 val projection = arrayOf( MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.ARTIST, MediaStore.Audio.Media.ALBUM, MediaStore.Audio.Media.DURATION, MediaStore.Audio.Media.SIZE ) context.contentResolver.query( audioUri, projection, null, null, null )?.use { cursor -> // Cursor中只会有一条数据(对应单个文件) if (cursor.moveToFirst()) { val title = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE)) val artist = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST)) ?: "未知艺术家" val album = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM)) ?: "未知专辑" val duration = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION)) val size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.SIZE)) // 这里可以根据需求处理元数据 println("标题:$title") println("艺术家:$artist") println("专辑:$album") println("时长:${duration / 1000}秒") println("文件大小:${size / 1024 / 1024}MB") } } }
视频文件示例
fun getSingleVideoMeta(context: Context, videoUri: Uri) { val projection = arrayOf( MediaStore.Video.Media.TITLE, MediaStore.Video.Media.DURATION, MediaStore.Video.Media.WIDTH, MediaStore.Video.Media.HEIGHT, MediaStore.Video.Media.SIZE, MediaStore.Video.Media.DATE_ADDED ) context.contentResolver.query( videoUri, projection, null, null, null )?.use { cursor -> if (cursor.moveToFirst()) { val title = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.TITLE)) val duration = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATION)) val width = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.WIDTH)) val height = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.HEIGHT)) val size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.SIZE)) val addedDate = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATE_ADDED)) println("标题:$title") println("时长:${duration / 1000}秒") println("分辨率:${width}x${height}") println("文件大小:${size / 1024 / 1024}MB") println("添加时间:${Date(addedDate * 1000)}") } } }
四、注意事项
- 务必使用
use函数包裹Cursor,确保Cursor自动关闭,避免内存泄漏 - 部分元数据字段可能为空,需要添加非空判断,避免空指针异常
- Android 10及以上不建议直接使用文件路径访问,优先通过Content URI操作媒体文件
内容的提问来源于stack exchange,提问作者Hanif Khan
相关产品推荐
相关产品推荐

