二、分区存储模式下使用 MediaStore 查询图片
首先 , 根据查询的位置 , 获取其对应的数据库操作 Uri ; 这里获取外置 SD 卡 Pictures 目录对应的 Uri 对象 ;
// 获取外置 SD 卡 Pictures 对应的 Uri 对象 var externalContentUri: Uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
然后 , 使用 SQLite 查询机制 , 查询对应图片的 Uri ; 查询 Pictures 目录下的 image.jpg 图片 ;
// 拼接查询语句 var selection: String = "${MediaStore.Images.Media.DISPLAY_NAME}=?"; // 查询语句参数 var selectionArgs: Array<String> = arrayOf("image.jpg"); // 查询 SQLite 数据库 var cursor = contentResolver.query( // 指定要查询的 Uri externalContentUri, // 指定要查询的列 null, // 指定查询语句 selection, // 指定查询参数 selectionArgs, // 排序规则 null )
最后 , 通过 Cursor 查询数据表中各个字段的信息 , 如 id 字段 , relative_path 相对路径字段 , data 绝对路径字段 , _display_name 文件名称字段 ;
// 先获取该图片在数据库中的 id , 然后通过 id 获取 Uri if (cursor != null && cursor.moveToFirst()){ // 获取第 0 行 _id 所在列的值 var id = cursor.getLong( // 获取 _id 所在列的索引 cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID) ) var path = cursor.getString( // 获取 relative_path 所在列的索引 cursor.getColumnIndexOrThrow(MediaStore.Images.Media.RELATIVE_PATH) ) var name = cursor.getString( // 获取 _display_name 所在列的索引 cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME) ) // 绝对路径 var absolutePath = cursor.getString( // 获取 data 所在列的索引 cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA) ) // 通过 _id 字段获取图片 Uri var uri = ContentUris.withAppendedId(externalContentUri, id); Log.i(TAG, "查询到的 Uri = $uri , 路径 = $path , 文件名称 = $name , 绝对路径 = $absolutePath") // 关闭游标 cursor.close() }
查询文件代码示例 :
/** * 查询所有的图片 */ fun queryImages(){ // 获取外置 SD 卡 Pictures 对应的 Uri 对象 var externalContentUri: Uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; // 拼接查询语句 var selection: String = "${MediaStore.Images.Media.DISPLAY_NAME}=?"; // 查询语句参数 var selectionArgs: Array<String> = arrayOf("image.jpg"); // 查询 SQLite 数据库 var cursor = contentResolver.query( // 指定要查询的 Uri externalContentUri, // 指定要查询的列 null, // 指定查询语句 selection, // 指定查询参数 selectionArgs, // 排序规则 null ) // 先获取该图片在数据库中的 id , 然后通过 id 获取 Uri if (cursor != null && cursor.moveToFirst()){ // 获取第 0 行 _id 所在列的值 var id = cursor.getLong( // 获取 _id 所在列的索引 cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID) ) var path = cursor.getString( // 获取 relative_path 所在列的索引 cursor.getColumnIndexOrThrow(MediaStore.Images.Media.RELATIVE_PATH) ) var name = cursor.getString( // 获取 _display_name 所在列的索引 cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME) ) // 绝对路径 var absolutePath = cursor.getString( // 获取 data 所在列的索引 cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA) ) // 通过 _id 字段获取图片 Uri var uri = ContentUris.withAppendedId(externalContentUri, id); Log.i(TAG, "查询到的 Uri = $uri , 路径 = $path , 文件名称 = $name , 绝对路径 = $absolutePath") // 关闭游标 cursor.close() } }
执行打印的结果 :
查询到的 Uri = content://media/external/images/media/42 , 路径 = Pictures/image/ , 文件名称 = image.jpg , 绝对路径 = /storage/emulated/0/Pictures/image/image.jpg
注意 : 该文件的 Uri 是 " content://media/external/images/media/42 " , 绝对路径是 " /storage/emulated/0/Pictures/image/image.jpg " ;
Uri 最后的 42 数字 , 就是在 " external.db " 数据库中 files 数据表中该 image.jpg 文件对应的 _id 字段数据 ;
绝对路径 在 Android 11 的 分区存储机制 中不能用来做任何操作 , 否则会产生崩溃 ;
对文件的操作 , 如 : 访问图片 , 删除图片 等操作 , 必须使用 Uri 进行操作 ;
三、相关文档资料
Android 文件处理参考文档 :
数据和文件存储概览 : https://developer.android.google.cn/training/data-storage
访问应用专属文件 : https://developer.android.google.cn/training/data-storage/app-specific#kotlin
保存到共享的存储空间 : https://developer.android.google.cn/training/data-storage/shared
管理存储设备上的所有文件 : https://developer.android.google.cn/training/data-storage/manage-all-files
分享文件 : https://developer.android.google.cn/training/secure-file-sharing
应用安装位置 : https://developer.android.google.cn/guide/topics/data/install-location
Android 存储用例和最佳做法 : https://developer.android.google.cn/training/data-storage/use-cases
FileProvider : https://developer.android.google.cn/reference/androidx/core/content/FileProvider
博客源码 :
GitHub : https://github.com/han1202012/File
CSDN : https://download.csdn.net/download/han1202012/18932254