【Android 文件管理】分区存储 ( 创建与查询图片文件 )

举报
韩曙亮 发表于 2022/01/10 22:51:03 2022/01/10
【摘要】 文章目录 一、分区存储模式下使用 MediaStore 插入图片二、分区存储模式下使用 MediaStore 查询图片三、相关文档资料 Android 分区存储系列博客 : 【Andr...

在这里插入图片描述

Android 分区存储系列博客 :





一、分区存储模式下使用 MediaStore 插入图片



在上一篇博客 【Android 文件管理】分区存储 ( MediaStore 文件操作 ) 中 , 创建了一个文本文件 , 并向其写出一个字符串 ;

创建文件时注意 , 使用 MediaStore 向 " external.db " 数据库 中插入了文件数据 , 只是生成了文件索引 , 如果不向文件中写出数据 , 并不会真正的创建文件 ; 插入数据后 , 依据返回的 android.net.Uri 类型打开输出流 , 然后通过该输出流写出数据 , 文件创建完成 ;


图片创建流程 :


首先 , 获取 操作数据库的 Uri ;

// 操作 external.db 数据库
// 获取 Uri 路径
var uri: Uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI

  
 
  • 1
  • 2
  • 3

其次 , 构造插入数据库的 ContentValues 数据结构 , 设置的 “external.db” 数据库中的 “files” 数据表的各个字段与 MediaStore 中的常量对应关系如下 :

  • MediaStore.Downloads.RELATIVE_PATH : relative_path
  • MediaStore.Downloads.DISPLAY_NAME : display_ame
  • MediaStore.Downloads.TITLE : tittle
  • MediaStore.Downloads.MIME_TYPE : mime_type
// 将要新建的文件的文件索引插入到 external.db 数据库中
// 需要插入到 external.db 数据库 files 表中, 这里就需要设置一些描述信息
var contentValues: ContentValues = ContentValues()

// 设置插入 external.db 数据库中的 files 数据表的各个字段的值
// 设置存储路径 , files 数据表中的对应 relative_path 字段在 MediaStore 中以常量形式定义
contentValues.put(MediaStore.Downloads.RELATIVE_PATH, "${Environment.DIRECTORY_MOVIES}/image")
// 设置文件名称
contentValues.put(MediaStore.Downloads.DISPLAY_NAME, "image.jpg")
// 设置文件标题, 一般是删除后缀, 可以不设置
contentValues.put(MediaStore.Downloads.TITLE, "image")
// 设置 MIME_TYPE
contentValues.put(MediaStore.Downloads.MIME_TYPE, "image/jpg")

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

再次 , 获取该上下文对应的 ContentResolver , 调用 insert 方法 , 将上述构建的 ContentValues 插入到数据库中 , 返回 Uri ;

// uri 表示操作哪个数据库 , contentValues 表示要插入的数据内容
var insert: Uri = contentResolver.insert(uri, contentValues)!!

  
 
  • 1
  • 2

最后 , 根据插入数据返回的 Uri , 打开输出流 , 然后向输出流中写出图片数据 ;

// 向 Download/hello/hello.jpg 文件中插入数据
var os: OutputStream = contentResolver.openOutputStream(insert)!!
var bitmap: Bitmap = BitmapFactory.decodeResource(resources, R.drawable.icon)
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os)
os.close()

  
 
  • 1
  • 2
  • 3
  • 4
  • 5

图片数据写出完成 , 输出流正式关闭 , 图片创建成功 ;


创建完成后 , 可以在 " Device Explorer " 面板中显示新创建的图片 ;

在这里插入图片描述


关于 图片 MIME_TYPE :

图片文件创建 与 文本文件创建 唯一的区别就是需要设置 MIME_TYPE 字段 , 根据传入的图片格式设置不同的 mimetype , 如 : 传入 jpeg 图片 , 则设置字段值为 “image/jpg” ;

保存图片文件时 , 传入的 MIME_TYPE 为 “image/jpg” , 如果传错了 , 写成 “vedio/mp3” , 创建文件时不会抛出异常 , 但是使用该文件时会出错 ;


图片创建部分代码示例 :

    /**
     * 创建图片文件
     * 在 Download 目录下创建 hello.txt
     */
    fun createImageFile(){

        // 操作 external.db 数据库
        // 获取 Uri 路径
        var uri: Uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI

        // 将要新建的文件的文件索引插入到 external.db 数据库中
        // 需要插入到 external.db 数据库 files 表中, 这里就需要设置一些描述信息
        var contentValues: ContentValues = ContentValues()

        // 设置插入 external.db 数据库中的 files 数据表的各个字段的值

        // 设置存储路径 , files 数据表中的对应 relative_path 字段在 MediaStore 中以常量形式定义
        contentValues.put(MediaStore.Downloads.RELATIVE_PATH, "${Environment.DIRECTORY_MOVIES}/image")
        // 设置文件名称
        contentValues.put(MediaStore.Downloads.DISPLAY_NAME, "image.jpg")
        // 设置文件标题, 一般是删除后缀, 可以不设置
        contentValues.put(MediaStore.Downloads.TITLE, "image")
        // 设置 MIME_TYPE
        contentValues.put(MediaStore.Downloads.MIME_TYPE, "image/jpg")

        // uri 表示操作哪个数据库 , contentValues 表示要插入的数据内容
        var insert: Uri = contentResolver.insert(uri, contentValues)!!

        // 向 Download/hello/hello.jpg 文件中插入数据
        var os: OutputStream = contentResolver.openOutputStream(insert)!!
        var bitmap: Bitmap = BitmapFactory.decodeResource(resources, R.drawable.icon)
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os)
        os.close()
    }

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34




二、分区存储模式下使用 MediaStore 查询图片



首先 , 根据查询的位置 , 获取其对应的数据库操作 Uri ; 这里获取外置 SD 卡 Pictures 目录对应的 Uri 对象 ;

// 获取外置 SD 卡 Pictures 对应的 Uri 对象
var externalContentUri: Uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;

  
 
  • 1
  • 2

然后 , 使用 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
)

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

最后 , 通过 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()
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

查询文件代码示例 :

    /**
     * 查询所有的图片
     */
    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()
        }
    }

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64

执行打印的结果 :

查询到的 Uri = content://media/external/images/media/42 , 路径 = Pictures/image/ , 文件名称 = image.jpg , 绝对路径 = /storage/emulated/0/Pictures/image/image.jpg

  
 
  • 1

注意 : 该文件的 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 文件处理参考文档 :


博客源码 :

在这里插入图片描述

文章来源: hanshuliang.blog.csdn.net,作者:韩曙亮,版权归原作者所有,如需转载,请联系作者。

原文链接:hanshuliang.blog.csdn.net/article/details/116984675

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。