数据和文件存储概览

Android 中有4种可使用的不同数据存储选项:

  • 内部文件存储:在设备文件系统中存储应用私有文件。
  • 外部文件存储:在共享外部文件系统中存储文件。此方式通常用于共享的用户文件,如照片。
  • 共享首选项:在键值对中存储私有的原始数据。
  • 数据库:在私有数据库中存储结构化数据。

文章目录

      • 1. 内部文件存储
      • 2. 外部文件存储
        • 2.0. 请求外部存储权限
        • 2.1. 公开文件
        • 2.2. 私有文件
      • 3. 分区存储

1. 内部文件存储

应用不需要任何系统权限即可读取和写入应用内部目录。默认情况下,保存至内部存储的文件是应用私有文件,其他应用(和用户)不能访问这些文件(除非拥有 Root 访问权限)。当用户卸载应用时,保存在内部存储中的文件也将随之移除。 在真机(Android 10)上尝试获取应用的内部文件存储目录:

context.getDataDir(): /data/user/0/com.package.name
context.getFilesDir():/data/user/0/com.package.name/files
context.getCacheDir(): /data/user/0/com.package.name/cache
context.getCodeCacheDir(): /data/user/0/com.package.name/code_cache
context.getNoBackupFilesDir(): /data/user/0/com.package.name/no_backup

应用不应该直接使用通过getDataDir()获得的路径,而应使用getFilesDir()getCacheDir()

  • getFilesDir()返回表示应用内部目录的File。调用context.openFileOutput()以获取会写入内部目录中的文件的FileOutputStream。调用context.openFileInput(name)并传入文件名可以打开现有文件。
  • getCacheDir()返回表示应用临时缓存文件的内部目录的File。如果需要缓存某些文件,则应使用File.createTempFile()。如果系统的存储空间不足,则可能会在不发出警告的情况下删除缓存文件。但是,不应依赖系统清理这些文件,而应始终自行维护缓存文件,使其占用的空间保持在合理的限制范围内。

2. 外部文件存储

2.0. 请求外部存储权限

Android 包含以下访问外部存储中的文件的权限:

  • READ_EXTERNAL_STORAGE允许应用访问外部存储设备中的文件。
  • WRITE_EXTERNAL_STORAGE允许应用在外部存储设备中写入和修改文件。拥有此权限的应用也会自动获得 READ_EXTERNAL_STORAGE权限。

从 Android 4.4(API 级别 19)开始,在特定于应用的目录中读取或写入文件不再需要任何与存储相关的权限。如果应用使用分区存储,则除非应用需要访问其他应用创建的文件,否则无需声明任何与存储相关的权限。

在请求存储权限并确认存储可用后,可以保存以下类型的文件:

2.1. 公开文件

指可供其他应用和用户自由访问的文件。在用户卸载应用后,这些文件仍然可供用户使用。
如果要将文件保存到其他应用可以访问的外部存储上,使用以下 API 之一:

  • 如果要保存照片、音频文件或视频剪辑,使用MediaStoreAPI。
  • 如果要保存任何其他文件(如 PDF 文档),使用ACTION_CREATE_DOCUMENTintent,这是存储访问框架的一部分。

如果不希望媒体扫描程序发现文件,需在特定于应用的目录中添加名为.nomedia的空文件(注意文件名中的句点前缀)。这可以防止媒体扫描程序读取应用的媒体文件并通过MediaStoreAPI 将它们提供给其他应用。

2.2. 私有文件

指存储在特定于应用的目录中的文件(使用Context.getExternalFilesDir()来访问)。这些文件在用户卸载应用时会被清除。 尽管这些文件在技术上可被用户和其他应用访问(因为它们存储在外部存储上),但它们不能为应用之外的用户提供价值。可以使用此目录来存储不想与其他应用共享的文件。在真机(Android 10)上尝试获取应用的外部文件存储目录:

context.getObbDir(): /storage/emulated/0/Android/obb/com.package.name
context.getExternalMediaDirs()[0]: /storage/emulated/0/Android/media/com.package.name
context.getExternalCacheDir(): /storage/emulated/0/Android/data/com.package.name/cache
context.getExternalFilesDir(null): /storage/emulated/0/Android/data/com.browser.hq/files
context.getExternalFilesDir(Environment.DIRECTORY_MUSIC):/storage/emulated/0/Android/data/com.package.name/files/Music

通过调用getExternalFilesDir()并传入指明想要的目录类型的名称来获取特定于应用的目录,务必使用由DIRECTORY_PICTURES这类 API 常量提供的目录名称。这些目录名称可确保系统正确地处理这些文件。例如,保存在DIRECTORY_RINGTONES中的文件会被系统媒体扫描程序归类为铃声,而不是音乐。如果没有适合的预定义子目录名称,可以调用getExternalFilesDir()并传入null,这会返回应用在外部存储上的专用目录的根目录。
context.getExternalFilesDirs()会返回一个File数组,因为这里的外部存储目录除了永久性存储空间的“外部”分区外,还可能会有可移动存储媒介(如 Micro SD 卡)。数组中的第一个条目被视为主要外部存储,除非该位置已满或不可用,否则应该一律使用该位置。无论外部存储空间是否可移动,这两种存储空间的 API 行为都是相同的。

3. 分区存储

为了让用户更好地管理自己的文件并减少混乱,以Android 10(API 级别 29) 及更高版本为目标平台的应用在默认情况下被赋予了外部存储设备的分区访问权限(即分区存储)。以 Android 9 或更低版本为目标平台的应用,可以通过将android:requestLegacyExternalStorage的值设为false来选择启用分区存储行为。除非应用需要访问存放在应用的专有目录以及MediaStore之外的文件,否则最好使用分区存储。

使用分区存储时,应用保存和访问自己创建的文件:

  1. 无需请求获得READ_EXTERNAL_STORAGEWRITE_EXTERNAL_STORAGE权限。
  2. 应存放在应用的专有目录(通过Context.getExternalFilesDir()访问)或者MediaStore

应用访问其他应用创建的文件:

  1. 需获得READ_EXTERNAL_STORAGE权限。
  2. 文件位于以下其中一个明确定义的媒体集合中:
    照片:存储在MediaStore.Images中。
    视频:存储在MediaStore.Video中。
    音频文件:存储在MediaStore.Audio中。

应用访问其他应用创建的任何其他文件:

  1. 必须使用存储访问框架,该框架允许用户选择特定文件。
  2. 对于/sdcard/DCIM/IMG1024.JPG这类路径不具有直接内核访问权限,即使拥有READ_EXTERNAL_STORAGE权限。要访问此类文件,应用必须使用MediaStore,并调用openFile()等方法。如果应用尝试通过原始文件系统视图打开这些文件,则会发生FileNotFoundException错误。

参考:
数据和文件存储概览 | Android 开发者 | Android Developers
└─ 将文件保存到设备存储空间中 | Android 开发者 | Android Developers
  ├─ 将文件保存到内部存储空间中 | Android 开发者 | Android Developers
  └─ 将文件保存到外部存储 | Android 开发者 | Android Developers
    └─ 管理分区外部存储访问 | Android 开发者 | Android Developers


以上是基于Android开发者官方中文版文档来进行整理的,然而官方英文版文档对Android数据存储的分类却不太一样。按英文版文档,系统同样提供了4个选项来保存应用程序数据:

  • 应用专属存储:存储只能应用使用的文件,可以存储在内部存储卷的专用目录中,也可以存储在外部存储卷的专用目录中。 使用内部存储的目录来保存其他应用程序不能访问的敏感信息。
  • 共享存储:存储应用打算与其他应用共享的文件,包括媒体、文档和其他文件。
  • 首选项:将私有的原始数据存储在键值对中。
  • 数据库:使用 Room 持久库在私有数据库中存储结构化数据。

其实这种分类方法与上述的分类方法大同小异,只不过将内部文件存储以及外部文件存储中的私有文件归类为应用专属存储,而外部文件存储中的公开文件归为共享存储。

参考:
Data and file storage overview | Android 开发者 | Android Developers
└─ Access app-specific files | Android 开发者 | Android Developers

你可能感兴趣的:(学习笔记,Android)