【Android(安卓)文件管理】分区存储 ( MediaStore 文件操作 )
文章目录
- 一、动态权限申请
- 二、MediaStore 操作文件
- 三、完整代码示例
-
- 1、MainActivity 核心代码
- 2、build.gradle 构建脚本
- 3、清单文件
- 五、相关文档资料
特别注意 Android 低版本中不能使用分区存储 API 操作文件 , 【错误记录】Android 低版本使用分区存储错误 ( IllegalArgumentException:no path was provided when inserting new file )
一、动态权限申请
进行 SD 卡读写操作前 , 必须先申请 SD 卡读写的动态权限 ;
动态权限参考 :
- 【Android 应用开发】Google 官方 EasyPermissions 权限申请库 ( 最简单用法 | 一行代码搞定权限申请 | 推荐用法 )
- 【Android 应用开发】Google 官方 EasyPermissions 权限申请库 ( 完整代码示例 | 申请权限 | 申请权限原理对话框 | 引导用户手动设置权限对话框 )
清单文件中的配置 :
<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>
构建脚本中的配置 :
dependencies { // 使用 Android X 的应用添加该依赖 implementation 'pub.devrel:easypermissions:3.0.0'}
Activity 中的权限申请源码 : 分支一是有权限的情况下的后续处理 , 分支二是申请动态权限 ;
@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 11 11 之后 , 不能使用 File 进行文件操作 , 需要使用 MediaStore 进行文件操作 ,
MediaStore 的如下内部类 Files , Images , Downloads , Audio , Video , 负责相应目录的文件操作 , 分别对应外置存储中的 Document , Pictures , Download , Music , Movies 目录 ;
如 : MediaStore 下的 Images 内部类 , 负责 Pictures 下的文件操作 ;
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 向其中插入数据 ;
获取数据库 :
// 操作 external.db 数据库 // 获取 Uri 路径 var uri: Uri = MediaStore.Files.getContentUri("external")
插入数据时 , 构造 ContentValues 数据结构 , 主要是设置 external.db 数据库中 files 数据表对应的条目 , 设置该条目的主要字段值 ;
构造 ContentValues 数据 :
// 将要新建的文件的文件索引插入到 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 将数据插入数据库中 ; 系统会自动创建对应的文件 ;
向数据库中插入数据 :
// uri 表示操作哪个数据库 , contentValues 表示要插入的数据内容 var insert: Uri = contentResolver.insert(uri, contentValues)!!
系统自动创建的文件是一个目录文件 , 向其中写出 “Hello World” 文本数据 , 即可完成相关文件创建 ;
通过返回的 Uri 打开输出流 , 向文件中写出数据 :
// 向 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 核心代码
package kim.hsl.fileimport android.Manifestimport android.content.ContentValuesimport android.net.Uriimport android.os.Bundleimport android.os.Environmentimport android.provider.MediaStoreimport android.widget.Toastimport androidx.appcompat.app.AppCompatActivityimport pub.devrel.easypermissions.AfterPermissionGrantedimport pub.devrel.easypermissions.EasyPermissionsimport java.io.BufferedOutputStreamimport java.io.OutputStreamclass 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 依赖库 ; ( 其它省略 )
dependencies { // 使用 Android X 的应用添加该依赖 implementation 'pub.devrel:easypermissions:3.0.0'}
3、清单文件
配置 SD 卡读写权限 ; ( 其它省略 )
<?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 文件处理参考文档 :
-
数据和文件存储概览 : 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/18832417
更多相关文章
- 让Ubuntu和Android同时运行(Ubuntu on Android)
- manifest文件
- Android上层启动过程的几个关键点
- Android(安卓)SDK相关介绍
- android九宫格实现
- Android解析ClassLoader(二)Android中的ClassLoader
- Android(安卓)Opencore
- Android对话框里面的输入值获取不到,空指针异常
- Android高手进阶教程(四)之----Android(安卓)中自定义属性(attr.