概述
文章目录
- 数据存储
- 存储空间分类
- 内部存储
- 外部存储
- 分区存储
- 内部存储
- 获取内部存储信息
- 写入数据
- 读取数据
- 写入内部缓存数据
- 读取内部缓存数据
- 外部私有存储
- 获取外部私有存储信息
- 写入外部私有存储
- 读取外部私有存储
- 写入外部私有缓存目录
- 读取外部私有缓存目录
- 外部非私有存储
- 分区存储
- 检查是否开启分区存储
- 保存数据
- 查询数据
- 删除数据
- 更新数据
- 使用SAF(Storage Access Framework)
- 获取SD卡所有权限
- 感谢
- 代码下载
数据存储
官网文档
存储空间分类
内部存储
- 内部存储只能被自己的应用访问,无需权限申请,app卸载后数据会被删,内部存储缓存的文件在内部空间不足时会被删除
getFileDir()
获取内部存储文件目录。路径:/data/user/0/package_name/files
getFileDir() 获取内部缓存文件目录
:/data/user/0/package_name/cache
外部存储
- 私有存储
- 空间相对较大,App卸载后会被删除,无需权限申请,缓存目录当空间不足时会被删除
getExternalFilesDir()
获取SD卡私有目录,路径:/storage/emulated/0/Android/data/package_name/files
getExternalCacheDir()
获取SD卡私有缓存目录,路径/storage/emulated/0/Android/data/package_name/cache
- 非私有存储
- 在Android10以下版本,使用外部非私有存储,需要权限申请
- 在Android10及以上版本,
getExternalStorageDirectory()
等api被废弃
分区存储
- Android10以上将媒体文件文件按类型保存在公共目录上,可以使用 MediaStore 访问媒体文件
内部存储
获取内部存储信息
//获取所有文件名
fileList().forEach {
Log.e("TAG", "内部存储文件:$it")
}
Log.e("TAG","内部文件存储路径:$filesDir")
Log.e("TAG","内部缓存文件存储路径:$cacheDir")
写入数据
val content = "hello 内部存储"
val fileName = "内部存储测试.txt"
val output = openFileOutput(fileName, MODE_PRIVATE)
output.write(content.toByteArray())
output.flush()
output.close()
读取数据
var content = ""
val fileName = "内部存储测试.txt"
val input = openFileInput(fileName)
val buffer = ByteArray(1024)
var len = 0
while ((input.read(buffer).also { len = it }) != -1) {
val str = String(buffer, 0, len)
content += str
}
input.close()
Log.e("TAG", "content: $content")
写入内部缓存数据
val content = "hello 内部缓存存储"
val fileName = "内部缓存存储测试.txt"
val file = File(cacheDir, fileName)
val output = FileOutputStream(file)
output.write(content.toByteArray())
output.flush()
output.close()
读取内部缓存数据
var content = ""
val fileName = "内部缓存存储测试.txt"
val file = File(cacheDir, fileName)
val input = FileInputStream(file)
val buffer = ByteArray(1024)
var len = 0
while ((input.read(buffer).also { len = it }) != -1) {
val str = String(buffer, 0, len)
content += str
}
input.close()
Log.e("TAG", "content: $content")
外部私有存储
获取外部私有存储信息
判断SD卡是否挂起
val ret = Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED
写入外部私有存储
val content = "hello 外部存储"
val fileName = "外部存储测试.txt"
val file = File(getExternalFilesDir("测试"), fileName)
val output = FileOutputStream(file)
output.write(content.toByteArray())
output.flush()
output.close()
读取外部私有存储
var content = ""
val fileName = "外部存储测试.txt"
val file = File(getExternalFilesDir("测试"), fileName)
val input = FileInputStream(file)
val buffer = ByteArray(1024)
var len = 0
while ((input.read(buffer).also { len = it }) != -1) {
val str = String(buffer, 0, len)
content += str
}
input.close()
Log.e("TAG", "content:$content")
写入外部私有缓存目录
val content = "hello 外部缓存存储"
val fileName = "外部缓存存储测试.txt"
val file = File(externalCacheDir, fileName)
val output = FileOutputStream(file)
output.write(content.toByteArray())
output.flush()
output.close()
读取外部私有缓存目录
var content = ""
val fileName = "外部缓存存储测试.txt"
val file = File(externalCacheDir, fileName)
val input = FileInputStream(file)
val buffer = ByteArray(1024)
var len = 0
while ((input.read(buffer).also { len = it }) != -1) {
val str = String(buffer, 0, len)
content += str
}
input.close()
Log.e("TAG", "content:$content")
外部非私有存储
//在Android10以下使用
val content = "hello 外部非私有存储测试"
val fileName = "外部非私有存储测试.txt"
val file = File(Environment.getExternalStorageDirectory(), fileName)
val output = FileOutputStream(file)
output.write(content.toByteArray())
output.flush()
output.close()
分区存储
-
开启分区存储后,我们访问媒体库的图片、音视频将会自动拥有读写权限,无需额外的权限申请;读取其他应用向媒体库贡献的图片、音视频,则必须申请READ_EXTERNAL权限_STORAGE
-
读取SD卡上非图片、音视频类文件,需要使用手机系统内置的文件选择器
检查是否开启分区存储
fun isScopedStorage(): Boolean =
Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && !Environment.isExternalStorageManager()
保存数据
/**
* 保存文档
*/
fun saveDocument() {
if (isScopedStorage()) {
val content = "Hello 分区存储,保存一些文本信息"
val externalUri = MediaStore.Files.getContentUri("external")
val dirName = "测试"
val fileName = "Hello.txt"
val path = Environment.DIRECTORY_DOWNLOADS + File.separator + dirName
val contentValues = ContentValues().apply {
put(MediaStore.Downloads.RELATIVE_PATH, path)
put(MediaStore.Downloads.DISPLAY_NAME, fileName)
put(MediaStore.Downloads.TITLE, fileName)
}
val uri: Uri? = contentResolver.insert(externalUri, contentValues)
uri?.let {
val output = contentResolver.openOutputStream(it)
val bos = BufferedOutputStream(output)
bos.write(content.toByteArray())
bos.flush()
bos.close()
output?.close()
}
}
}
/**
* 保存图片
*/
fun saveImage() {
if (isScopedStorage()) {
val imageName = "hello.jpg"
val dirName = "图片测试"
val path = Environment.DIRECTORY_PICTURES + File.separator + dirName
val contentValue = ContentValues().apply {
put(MediaStore.Images.ImageColumns.RELATIVE_PATH, path)
put(MediaStore.Images.ImageColumns.DISPLAY_NAME, imageName)
put(MediaStore.Images.ImageColumns.MIME_TYPE, "image/jpg")
put(MediaStore.Images.ImageColumns.TITLE, imageName)
}
val uri =
contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValue)
val bitmap = BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher)
uri?.let {
val output = contentResolver.openOutputStream(it)
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, output)
output?.close()
}
}
}
查询数据
if (isScopedStorage()) {
val imageName = "hello.jpg"
val uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
val selection = MediaStore.Images.Media.DISPLAY_NAME + "=?"
var args = arrayOf(imageName)
val cursor = contentResolver.query(uri, null, selection, args, null)
cursor?.let {
if (it.moveToFirst()) {
val id = it.getLong(it.getColumnIndexOrThrow(MediaStore.Images.Media._ID))
queryUri = ContentUris.withAppendedId(uri, id)
binding.imageView.setImageURI(queryUri)
Log.e("TAG", "查询成功: $queryUri")
}
it.close()
}
}
删除数据
if (isScopedStorage()) {
queryUri?.let {
val row: Int = contentResolver.delete(it, null, null)
Log.e("TAG", "删除成功: $row")
}
}
更新数据
if (isScopedStorage()) {
queryUri?.let {
val contentValues = ContentValues().apply {
put(MediaStore.Images.ImageColumns.DISPLAY_NAME, "hello_01.jpg")
}
val update: Int = contentResolver.update(it, contentValues, null, null)
Log.e("TAG", "修改成功:$update")
}
}
使用SAF(Storage Access Framework)
使用非图片、音视频的文件时,比如PDF文件,这时候不能使用MediaStore,只能使用文件选择器
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.type = "image/*"
startActivityForResult(intent, 222)
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
222 -> {
if (resultCode == Activity.RESULT_OK && data != null) {
val uri = data.data
uri?.let {
binding.safImageView.setImageBitmap(
BitmapFactory.decodeStream(contentResolver.openInputStream(uri))
)
}
}
}
}
}
获取SD卡所有权限
Android 11中强制启用Scoped Storage是为了更好地保护用户的隐私,以及提供更加安全的数据保护。对于绝大部分应用程序来说,使用MediaStore提供的API就已经可以满足大家的开发需求了。
拥有对整个SD卡的读写权限,在Android 11上被认为是一种非常危险的权限,同时也可能会对用户的数据安全造成比较大的影响。
对于这类危险程度比较高的权限,Google通常采用的做法是,使用Intent跳转到一个专门的授权页面,引导用户手动授权,比如悬浮窗,无障碍服务等。
没错,在Android 11中,如果你想要管理整个设备上的文件,也需要使用类似的技术。
在AndroidManifest文件中声明权限
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.myapplication">
<uses-permission
android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
</manifest>
在代码中开启权限
fun requestAllFilesAccessPermission() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R || Environment.isExternalStorageManager()) {
Toast.makeText(this,
"We can access all files on external storage now",
Toast.LENGTH_SHORT).show()
} else {
val builder = AlertDialog.Builder(this)
.setTitle("Tip")
.setMessage("We need permission to access all files on external storage")
.setPositiveButton("OK") { _, _ ->
val intent = Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION)
startActivityForResult(intent, 333)
}
.setNegativeButton("Cancel", null)
builder.show()
}
}
权限开启成功后,可以自由操作SD卡文件了
感谢
https://juejin.cn/post/6991197604969185311#heading-5
https://guolin.blog.csdn.net/article/details/105419420
https://guolin.blog.csdn.net/article/details/113954552
https://juejin.cn/post/6844904063432130568
代码下载
最后
以上就是爱笑大米为你收集整理的Android 文件数据存储总结数据存储的全部内容,希望文章能够帮你解决Android 文件数据存储总结数据存储所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复