android储存机制

Android系统分为内部存储和外部存储:

  1. 内部存储:手机系统自带的存储,一般空间都比较小
  2. 外部存储:分为手机内置外部储存和SD卡外部储存

应用在安装之后,系统会自动在内部存储和外部存储,分别建立应用的私有存储区域。
a. 内部存储 : data/user/0/应用包名
b. 外部存储 : storage/emulated/0/android/data/应用包名

内外部存储图解:
在这里插入图片描述

了解分区存储

Android 10版本中,Google推出 分区存储(scoped storage)的功能。

背景:

分区存储功能是针对内置的外部存储来说的,很多应用喜欢在外部存储的根目录创建自己的文件夹,比如:storage/emulated/0/***

这样做的好处:

  1. 当不断向该目录存储时,应用自己的容量不会变化;
  2. 当应用卸载时,该目录下文件不会被删除,可用于保存一些可持久性的文件。

但是也有坏处:

  1. 对用户来说,会有很多垃圾文件存在于手机中;
  2. 只要获取到Read 和 Write权限,就可以随意访问外部存储的任何目录,信息安全存在隐患。

分区存储:

  1. 每个应用向自己的私有目录读写文件,不需要读写权限。私有文件目录具体路径: storage/emulated/0/android/data/packageName/ ,获取方法: Context#getExternalFilesDir()

  2. 应用即使获取了读写权限,也无法访问其他应用的私有目录。

  3. 当应用需要获取媒体文件时,通过 MediaStore API 向公共存储目录DCIM、Music或者Movie获取。同样写媒体文件也是如此。并且读写自己的文件时不需要申请权限。 只有读其他应用的媒体文件时才会需要申请READ_EXTERNAL_STORAGE权限。
    (更新:Android11为目标平台时,可以使用文件直接路径去访问媒体,这是在Android10上没有的,应用的性能会略有下降,还是推荐使用MediaStore )

  4. 当应用需要获取其他非媒体文件时,比如doc、pdf文件,需要使用 系统的文件选择器SAF 来进行访问。

  5. 所以WRITE_EXTERNAL_STORAGE权限,在未来的Android11版本里,会被废弃。 (写文件不需要权限,只能在私有目录和公共目录写文件)

分区存储适配

旧版存储位置迁移

除了应用的私有目录和公共目录,其他位置都称为 旧版存储位置,我们需要将旧版存储位置的数据迁移到能兼容分区存储的位置。

  1. 如果以Android 11为目标平台的应用,需要在manifest清单中标记preserveLegacyExternalStorage 为true,这样在Android11的机器上覆盖安装时,才能访问旧版存储位置,卸载重装会失效。

  2. 如果以Android10为目标平台,覆盖安装可以访问旧版存储,且将manifest清单中标记requestLegacyExternalStorage 为true,在Android10机器上重新安装也能访问旧版存储位置。在Android11的机器上两种安装方式都会失效,需要加上preserveLegacyExternalStorage = true,且覆盖安装才能访问旧版存储位置。卸载重装会失效。

  3. 如果以Android 9及以下为目标平台时,就能正常的进行文件移动。将应用在外部存储器根目录的保存的数据中,如果能接受随应用的卸载而删除的文件,迁移至storage/emulated/0/android/data/packageName/目录下。需要和其他应用共享的媒体文件,迁移至媒体存储位置。

正确使用读写API

  1. 只在外部存储的应用私有目录下,用直接路径读写文件
  2. 访问或者共享媒体文件,使用MediaStore在公共目录下读写文件
  3. 访问或者共享非媒体文件,使用系统的文件选择器SAF在公共目录Download下读写文件

存储路径

一般我们可以通过 Context 和 Environment 相关的方法获取文件存取的路径。

1. 内部存储
a. 根目录($rootDir):/data,通过 Environment.getDataDirectory() 获取。

b. 应用程序目录( a p p l i c a t i o n D i r ) : applicationDir): applicationDir)rootDir/data/包名(不一定,不同设备可能不同)

应用缓存目录:$applicationDir/cache,通过Context.getCacheDir()获取。

应用文件目录:$applicationDir/files,通过Context.getFilesDir()获取。Context.getFileStreamPath(String name)返回以name为文件名的子文件目录,若name为空,则返回文件根目录。假设我们的应用程序包名为com.learn.test,路径如下:

Environment.getDataDirectory():      /data
Context.getCacheDir():               /data/data/com.learn.test/cache
Context.getFilesDir():               /data/data/com.learn.test/files
Context.getFileStreamPath(""):       /data/data/com.learn.test/files
Context.getFileStreamPath("test"):   /data/data/com.learn.test/files/test

2.外部存储

a. 根目录($rootDir):/storage/emulated/0(不一定,不同设备可能不同),通过 Environment.getExternalStorageDirectory() 获取。

b. 应用程序目录( a p p l i c a t i o n D i r ) : applicationDir): applicationDir)rootDir/Andorid/data/包名

应用缓存目录:$applicationDir/cache,通过Context.getExternalCacheDir()获取。

应用文件目录:$applicationDir/files,通过Context.getExternalFilesDir(String type),type为空字符串时获取。type系统给我们提供了很多常用的类型,比如图片和下载等等:

public static String DIRECTORY_MUSIC = "Music";
public static String DIRECTORY_ALARMS = "Alarms";
public static String DIRECTORY_NOTIFICATIONS = "Notifications";
public static String DIRECTORY_PICTURES = "Pictures";
public static String DIRECTORY_MOVIES = "Movies";
public static String DIRECTORY_DOWNLOADS = "Download";
public static String DIRECTORY_DCIM = "DCIM";
public static String DIRECTORY_DOCUMENTS = "Documents";

假设我们的应用程序包名为com.learn.test,路径如下:

Environment.getExternalStorageDirectory():               /storage/emulated/0
Context.getExternalCacheDir():                           /storage/emulated/0/Android/data/com.learn.test/cache
Context.getExternalFilesDir(""):                         /storage/emulated/0/Android/data/com.learn.test/files
Context.getExternalFilesDir("test"):                     /storage/emulated/0/Android/data/com.learn.test/files/test
Context.getExternalFilesDir(Environment.DIRECTORY_PICTURES):    /storage/emulated/0/Android/data/com.learn.test/files/Pictures

公共存储目录: 我们可以在外部存储上新建任意文件夹,不过在6.0及之后的系统需要动态申请权限,这些目录的内容不会随着应用的卸载而消失。如:

Environment.getExternalStorageDirectory():                     /storage/emulated/0
Environment.getExternalStoragePublicDirectory(""):             /storage/emulated/0
Environment.getExternalStoragePublicDirectory("test"):         /storage/emulated/0/test
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)/storage/emulated/0/Pictures

以上内容转自下面两篇文章,觉得写的很好,我统一了一下

  1. Android - 文件系统与Android11 分区存储
  2. Android存储及getCacheDir()、getFilesDir()、getExternalFilesDir()、getExternalCacheDir()区别
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值