前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Android 文件管理】分区存储 ( MediaStore 文件操作 )

【Android 文件管理】分区存储 ( MediaStore 文件操作 )

作者头像
韩曙亮
发布2023-03-29 12:38:31
2.4K0
发布2023-03-29 12:38:31
举报
文章被收录于专栏:韩曙亮的移动开发专栏

文章目录

特别注意 Android 低版本中不能使用分区存储 API 操作文件 , 【错误记录】Android 低版本使用分区存储错误 ( IllegalArgumentException:no path was provided when inserting new file )

一、动态权限申请


进行 SD 卡读写操作前 , 必须先申请 SD 卡读写的动态权限 ;

动态权限参考 :

清单文件中的配置 :

代码语言:javascript
复制
<manifest 
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="kim.hsl.file">

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

    <application />
</manifest>

构建脚本中的配置 :

代码语言:javascript
复制
dependencies {
    // 使用 Android X 的应用添加该依赖
    implementation 'pub.devrel:easypermissions:3.0.0'
}

Activity 中的权限申请源码 : 分支一是有权限的情况下的后续处理 , 分支二是申请动态权限 ;

代码语言:javascript
复制
    @AfterPermissionGranted( 100 )
    fun doSomethingWithPermissions(){
        if(EasyPermissions.hasPermissions(this,
                        Manifest.permission.READ_EXTERNAL_STORAGE,
                        Manifest.permission.WRITE_EXTERNAL_STORAGE)){

            // 分支一 : 如果有上述权限, 执行该操作
            Toast.makeText(this, "权限申请通过", Toast.LENGTH_LONG).show()
        }else{
            // 分之二 : 如果没有上述权限 , 那么申请权限
            EasyPermissions.requestPermissions(
                    this,
                    "权限申请原理对话框 : 描述申请权限的原理",
                    100,

                    Manifest.permission.READ_EXTERNAL_STORAGE,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE
            )
        }
    }

二、MediaStore 操作文件


在 Android

11

之后 , 不能使用 File 进行文件操作 , 需要使用 MediaStore 进行文件操作 ,

MediaStore 的如下内部类 Files , Images , Downloads , Audio , Video , 负责相应目录的文件操作 , 分别对应外置存储中的 Document , Pictures , Download , Music , Movies 目录 ;

如 : MediaStore 下的 Images 内部类 , 负责 Pictures 下的文件操作 ;

代码语言:javascript
复制
package android.provider;

public final class MediaStore {
    public static final class Images {
        public Images() {
            throw new RuntimeException("Stub!");
        }
    }
}

一个 文本文件 , 只能存储在 Download 和 Documents 目录下 , Download 目录可以存放任何类型的文件 , Documents 目录只能存储文本文件 ;

首先通过 MediaStore 获取 Files 内部类对象 , 调用该内部类的 getContentUri(“external”) , 即可获取在 【Android 文件管理】分区存储 ( 分区存储机制 和 文件索引数据 ) 四、文件索引数据库 博客章节提到的文件索引数据库 , 然后就可以通过 ContentValues 向其中插入数据 ;

获取数据库 :

代码语言:javascript
复制
        // 操作 external.db 数据库
        // 获取 Uri 路径
        var uri: Uri = MediaStore.Files.getContentUri("external")

插入数据时 , 构造 ContentValues 数据结构 , 主要是设置 external.db 数据库中 files 数据表对应的条目 , 设置该条目的主要字段值 ;

构造 ContentValues 数据 :

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

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

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

ContentValues 构造成功后 , 使用 ContentResolver 将数据插入数据库中 ; 系统会自动创建对应的文件 ;

向数据库中插入数据 :

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

系统自动创建的文件是一个目录文件 , 向其中写出 “Hello World” 文本数据 , 即可完成相关文件创建 ;

通过返回的 Uri 打开输出流 , 向文件中写出数据 :

代码语言:javascript
复制
        // 向 Download/hello/hello.txt 文件中插入数据
        var os: OutputStream = contentResolver.openOutputStream(insert)!!
        var bos = BufferedOutputStream(os)
        bos.write("Hello World".toByteArray())
        bos.close()

启动 Android 11 系统的模拟器 , 然后部署该应用 , 文件创建成功 ;

三、完整代码示例


1、MainActivity 核心代码

代码语言:javascript
复制
package kim.hsl.file

import android.Manifest
import android.content.ContentValues
import android.net.Uri
import android.os.Bundle
import android.os.Environment
import android.provider.MediaStore
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import pub.devrel.easypermissions.AfterPermissionGranted
import pub.devrel.easypermissions.EasyPermissions
import java.io.BufferedOutputStream
import java.io.OutputStream

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 动态权限获取
        doSomethingWithPermissions()

    }

    @AfterPermissionGranted( 100 )
    fun doSomethingWithPermissions(){
        if(EasyPermissions.hasPermissions(this,
                        Manifest.permission.READ_EXTERNAL_STORAGE,
                        Manifest.permission.WRITE_EXTERNAL_STORAGE)){

            // 分支一 : 如果有上述权限, 执行该操作
            Toast.makeText(this, "权限申请通过", Toast.LENGTH_LONG).show()

            // Android 11 中创建文件
            createFile()

        }else{
            // 分支二 : 如果没有上述权限 , 那么申请权限
            EasyPermissions.requestPermissions(
                    this,
                    "权限申请原理对话框 : 描述申请权限的原理",
                    100,

                    Manifest.permission.READ_EXTERNAL_STORAGE,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE
            )
        }
    }

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

        // 操作 external.db 数据库
        // 获取 Uri 路径
        var uri: Uri = MediaStore.Files.getContentUri("external")

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

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

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

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

        // 向 Download/hello/hello.txt 文件中插入数据
        var os: OutputStream = contentResolver.openOutputStream(insert)!!
        var bos = BufferedOutputStream(os)
        bos.write("Hello World".toByteArray())
        bos.close()
    }

}

2、build.gradle 构建脚本

引入 pub.devrel:easypermissions:3.0.0 依赖库 ; ( 其它省略 )

代码语言:javascript
复制
dependencies {
    // 使用 Android X 的应用添加该依赖
    implementation 'pub.devrel:easypermissions:3.0.0'
}

3、清单文件

配置 SD 卡读写权限 ; ( 其它省略 )

代码语言:javascript
复制
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="kim.hsl.file">

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

</manifest>

五、相关文档资料


Android 文件处理参考文档 :

博客源码 :

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-05-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章目录
  • 一、动态权限申请
  • 二、MediaStore 操作文件
  • 三、完整代码示例
    • 1、MainActivity 核心代码
      • 2、build.gradle 构建脚本
        • 3、清单文件
        • 五、相关文档资料
        相关产品与服务
        对象存储
        对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档