参考文章


Android 数据存储—外部存储(SD卡)

Android_数据存储_File

API Guides

概述


Android 提供了多种选项来保存永久性应用数据,这一过程也有叫做是数据的持久化存储。我们可以根据我们特定的业务需求来选择合适的存储方式。

数据存储选项


选项 存储方式
SharedPreferences 存储 用键值对存储私有原始数据
内部存储 在设备内存中存储私有数据
外部存储 在共享的外部存储中存储公共数据
SQLite 数据库存储 在私有的数据库中存储结构化数据
网络存储 通过自己的网络服务器存储数据

说明:
SharedPreferences 这个类可以对应用的一些参数配置、设置等数据进行存储。

Android 为我们提供了一个组件 ContentProvider,我们可以使用它将自己应用的数据(甚至是私有数据),添加自己希望的任何限制来公开其它应用对自己应用数据的读/写访问权限,这里不做过多说明。

SharedPreferences


SharedPreferences 这个类提供了一个通用的框架,我们可以很方便的使用它来保存任何类型的数据:布尔型、浮点型、整型、长整型和字符型。它保存在 data\data\<应用程序包名>\shared_prefs\ 下,可以使用虚拟机查看。

示例代码如下

      public static final String PREFS_NAME = "MyPrefsFile";// We need an Editor object to make preference changes.// All objects are from android.context.ContextSharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);SharedPreferences.Editor editor = settings.edit();editor.putBoolean("silentMode", mSilentMode);// Commit the edits!editor.commit();...// Restore preferencesSharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);boolean silent = settings.getBoolean("silentMode", false);

内部存储


在设备的内部存储中保存文件。默认情况下,保存到内部存储的文件是应用的私有文件,其他应用(和用户)不能访问这些文件。 当用户卸载您的应用时,这些文件也会被移除。文件会保存在 /data/data/应用程序包名/files 目录下,如上图所示。

文件写入内部存储的步骤

  1. 调用 openFileOutput() 方法,返回一个 FileOutputStream 对象;
  2. 通过 FileOutputStream 对象,调用 write() 方法写入到文件;
  3. 通过 FileOutputStream 对象,调用 close() 关闭流;

示例代码如下

String FILENAME = "hello_file";
String string = "hello world!";FileOutputStream fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
fos.write(string.getBytes());
fos.close();

MODE_PRIVATE 将会创建文件(或替换具有相同名称的文件),并将其设为应用的私有文件。其他可用模式包括:MODE_APPEND 如果文件存在,则在后面追加数据、MODE_WORLD_READABLEMODE_WORLD_WRITEABLE

注意:自 API 级别 17 以来,常量 MODE_WORLD_READABLEMODE_WORLD_WRITEABLE 已被弃用。从 Android N 开始,使用这些常量将会导致引发 SecurityException。这意味着,面向 Android N 和更高版本的应用将无法按名称共享私有文件,尝试共享 “file://”URI 将会导致引发 FileUriExposedException。 如果自己的应用需要与其他应用共享私有文件,则可以通过 FileProviderFLAG_GRANT_READ_URI_PERMISSION 配合使用。这里不做过多说明。

从内部存储中读取文件步骤

  1. 调用 openFileInput() 方法,返回一个 FileInputStream 对象;
  2. 通过 FileInputStream 对象,调用 read() 方法读取文件字节;
  3. 通过 FileInputStream 对象,调用 close() 关闭流;

提示:对于静态文件(就是那些不会改变的文件,比如 CSS 文件,JS 文件,提示音等),我们可以将它们放在项目的 res/raw/ 目录中或 assets/ 目录中。然后通过资源 id 调用 openRawResource() 或其它方法返回一个 InputStream 对象,通过流读取文件。

使用缓存文件

如果您想要缓存一些数据,而不是永久存储这些数据,应该使用 getCacheDir() 来打开一个 File,它表示您的应用应该将临时缓存文件保存到的内部存储目录。

当设备的内部存储空间不足时,Android 可能会删除这些缓存文件以回收空间。 但我们不应该依赖系统来为您清理这些文件, 而应该始终自行维护缓存文件,使其占用的空间保持在合理的限制范围内(例如 1 MB)。 当用户卸载应用时,这些文件也会被移除。

内部存储的缓存文件读取步骤和上面的普通文件读取类似,只是将上面的 FILENAME换成了 getCacheDir() + File.separator + FILE_NAME

示例代码如下


FileOutputStream fos = openFileOutput(getCacheDir() + File.separator + FILE_NAME, Context.MODE_PRIVATE);FileOutputStream fis = FileInputStream(getCacheDir() + File.separator + FILE_NAME, Context.MODE_PRIVATE);

其它实用方法

方法 含义
getFilesDir( ) 获取应用中存储内部文件的文件系统目录的绝对路径
getDir( ) 在应用的内部存储空间内创建(或打开现有的)目录
deleteFile( ) 删除保存在应用内部存储的文件
fileList( ) 返回应用当前保存的一系列文件

外部存储


外部存储可能是可移除的存储介质(例如 SD 卡)或内部(不可移除)存储。 保存到外部存储的文件是全局可读取文件,而且可由用户修改这些文件。有两种类型的文件,一类是 可与其它应用共享的文件,还有就是 应用私有文件

标准手机的 SD 卡根目录是: /mnt/sdcard/, 其他国产手机 SD 卡的根目录各不相同,如 /storage/emulated/0/ 等。这里以 /mnt/sdcard/为例。

使用 Scoped Directory(作用域目录) 访问

在 Android 7.0 或更高版本中,如果应用需要访问外部存储上的特定目录,官方推荐使用作用域目录访问。 作用域目录访问可简化应用访问标准外部存储目录(例如 Pictures 目录)的方式,并提供简单的权限 UI,清楚地详细介绍应用正在请求访问的目录。这里不做过多说明。

获取外部存储的访问权限

要读取或写入外部存储上的文件,应用必须获取 READ_EXTERNAL_STORAGEWRITE_EXTERNAL_STORAGE 系统权限。

如果应用同时需要读取和写入文件,则只需请求 WRITE_EXTERNAL_STORAGE 权限,因为此权限也隐含了读取权限要求。

注意:从 Android 4.4 开始,如果应用仅仅读取或写入应用外部存储的私有文件,则不需要这些权限。

检查外部存储的可用性

在使用外部存储执行任何工作之前,应始终调用 getExternalStorageState() 以检查外部存储是否可用。存储介质可能已装载到计算机,处于缺失、只读或其他某种状态。

示例代码如下

/* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable() {String state = Environment.getExternalStorageState();if (Environment.MEDIA_MOUNTED.equals(state)) {
        return true;}
    return false;
}

getExternalStorageState() 方法可能返回当前应用的其它状态(例如存储介质是否处于共享 [连接到计算]、完全缺失、错误移除等状态)。当应用返回这些状态时,我们可以使用这些状态通知给用户。

保存可与其它应用共享的文件

文件是可以被自由访问,且文件的数据对其它应用或者用户来说都是有意义的,当应用被卸载之后,其卸载前创建的文件仍然保留。

下表是一些外部存储共享文件的根目录说明

根目录 含义
/mnt/sdcard/Music/ 媒体扫描器把在这个目录中找到所有媒体文件作为用户音乐
/mnt/sdcard/Podcasts/ 媒体扫描器把在这个目录中找到的所有媒体文件作为音/视频的剪辑片段
/mnt/sdcard/Ringtones/ 媒体扫描器把在这个目录中找到的所有媒体文件作为铃声
/mnt/sdcard/Alarms/ 媒体扫描器把在这个目录中找到的所有媒体文件作为闹钟的声音
/mnt/sdcard/Pictures/ 所有的图片(不包括那些用照相机拍摄的照片)
/mnt/sdcard/Movies 所有的电影(不包括那些用摄像机拍摄的视频)
/mnt/sdcard/Download/ 其他下载的内容

一般而言,应该将用户可通过自己的应用获取的新文件保存到设备上的“公共”位置,以便其它应用能够在其中访问这些文件,并且用户也能轻松地从该设备复制这些文件。 执行此操作时,应使用共享的公共目录之一,例如 Music/Pictures/Ringtones/ 等。

要获取表示相应的公共目录的 File,需调用 getExternalStoragePublicDirectory() 方法,向其传递需要的目录类型,例如 DIRECTORY_MUSICDIRECTORY_PICTURESDIRECTORY_RINGTONES 或其他类型。然后将文件保存到相应的媒体类型目录,系统的媒体扫描程序可以在系统中正确地归类存储的文件(例如铃声在系统设置中显示为铃声而不是音乐)。

示例代码如下

public File getAlbumStorageDir(String albumName) {// Get the directory for the user's public pictures directory.// 公共图片目录中创建了一个用于新相册的目录File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), albumName);if (!file.mkdirs()) {Log.e(LOG_TAG, "Directory not created");}return file;
}

保存应用私有文件

如果应用正在处理的文件不适合其它应用使用(例如仅供自己应用使用的图形纹理或音效),则应该通过调用 getExternalFilesDir() 来使用外部存储上的私有存储目录。此方法还会采用 type 参数指定子目录的类型(例如 DIRECTORY_MOVIES)。 如果我们不需要特定的媒体目录,可传递 null 以接收应用私有目录的根目录。

所有应用程序的 外部存储的私有文件 都放在 SD 卡根目录的 Android/data/下,目录形式如:/mnt/sdcard/Android/data/< 应用程序包名 >/files

从 Android 4.4 开始,读取或写入应用私有目录中的文件不再需要 READ_EXTERNAL_STORAGEWRITE_EXTERNAL_STORAGE 权限。 因此,我们可以通过添加 maxSdkVersion 属性来声明,只能在较低版本的 Android 中请求该权限:

<manifest ...><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"android:maxSdkVersion="18" />...
</manifest>

有时,已分配某个内部存储器分区用作外部存储的设备可能还提供了 SD 卡槽。在使用运行 Android 4.3 和更低版本的这类设备时,getExternalFilesDir() 方法将仅提供内部分区的访问权限,而我们应用无法读取或写入 SD 卡。不过,从 Android 4.4 开始,可通过调用 getExternalFilesDirs() 来同时访问两个位置,该方法将会返回包含各个位置条目的 File 数组。 数组中的第一个条目被视为外部主存储;除非该位置已满或不可用,否则应该使用该位置。 如果我们希望在支持 Android 4.3 和更低版本的同时访问两个可能的位置,可使用支持库中的静态方法 ContextCompat.getExternalFilesDirs()。 在 Android 4.3 和更低版本中,此方法也会返回一个 File 数组,但其中始终仅包含一个条目

注意:尽管 MediaStore 内容提供程序不能访问 getExternalFilesDir()getExternalFilesDirs() 所提供的目录,但其他具有 READ_EXTERNAL_STORAGE 权限的应用仍可访问外部存储上的所有文件,包括上述文件。 如果我们需要完全限制自己应用文件的访问权限,则应该转而将文件写入到内部存储

保存缓存文件

要打开缓存文件保存到外部存储目录的 File,需调用 getExternalCacheDir()。 如果用户卸载了应用,这些文件也会被自动删除。

与前述 ContextCompat.getExternalFilesDirs() 方法相似,我们可以通过调用 ContextCompat.getExternalCacheDirs() 方法来访问辅助外部存储(如果可用)上的缓存目录。

缓存文件放在目录 /mnt/sdcard/Android/data/< package_name>/cache下。

提示 :为节省文件空间并保持应用性能,我们应该在应用的整个生命周期内仔细管理缓存文件并移除其中不再需要的文件,这一点非常重要。

使用数据库


Android 提供了对 SQLite 数据库的完全支持。

创建新 SQLite 数据库的推荐方法是创建 SQLiteOpenHelper 的子类并覆盖 onCreate() 方法,在此方法中,我们可以执行 SQLite 命令以创建数据库中的表。

示例代码如下

public class DictionaryOpenHelper extends SQLiteOpenHelper {private static final int DATABASE_VERSION = 2;private static final String DICTIONARY_TABLE_NAME = "dictionary";private static final String DICTIONARY_TABLE_CREATE ="CREATE TABLE " + DICTIONARY_TABLE_NAME + " (" +KEY_WORD + " TEXT, " +KEY_DEFINITION + " TEXT);";DictionaryOpenHelper(Context context) {super(context, DATABASE_NAME, null, DATABASE_VERSION);}@Overridepublic void onCreate(SQLiteDatabase db) {db.execSQL(DICTIONARY_TABLE_CREATE);}
}

然后使用已定义的构造函数获取 SQLiteOpenHelper 实现的实例。 要从数据库执行写入和读取操作时,分别调用 getWritableDatabase()getReadableDatabase()。二者都会返回一个表示数据库的 SQLiteDatabase 对象,并提供用于 SQLite 操作的方法,使用 SQLiteDatabase query() 方法来执行 SQLite 查询。

每个 SQLite 查询都会返回一个指向该查询找到的所有行的 Cursor。 我们可以使用 Cursor 机制来浏览数据库查询结果,以及读取行和列。

Android SDK 包含一项 sqlite3 数据库工具,利用此工具可以浏览表内容,运行 SQL 命令,以及在 SQLite 数据库上执行其他实用功能。

使用网络存储


通过网络来存储和检索有关自己的网络服务的数据。

参考文章

Android 数据存储—外部存储(SD卡)

Android_数据存储_File

API Guides

Android 数据存储相关推荐

  1. Android数据存储——2.文件存储_B_资源文件

    今天学习Android数据存储--文件存储_资源文件 把资源文件mybook.txt放入项目目录下的res资源文件夹下的raw文件夹下(没有则新建),PS:mybook.txt存为UTF-8编码. X ...

  2. Android数据存储——2.文件存储_C_DOM解析XML文档

    今天学习Android数据存储--文件存储_DOM解析XML文档 位于org.w3c.dom操作XML会比较简单,就是将XML看做是一颗树,DOM就是对这颗树的一个数据结构的描述,但对大型XML文件效 ...

  3. Android数据存储之GreenDao 3.0 详解

    前言: 今天一大早收到GreenDao 3.0 正式发布的消息,自从2014年接触GreenDao至今,项目中一直使用GreenDao框架处理数据库操作,本人使用数据库路线 Sqlite----> ...

  4. < Android数据存储> 任务二 应用程序数据文件夹里的文件读写

    :zh]Android中提供了两个方法用来打开应用程序的数据文件夹IO流. 1.FileInputStream openFileInput(String name):参数name表示某个文件名,该方法 ...

  5. 5 Android数据存储 任务二 应用程序数据文件夹里的文件读写 ,

    Android中提供了两个方法用来打开应用程序的数据文件夹IO流. 1.FileInputStream openFileInput(String name):参数name表示某个文件名,该方法用于打开 ...

  6. Android数据存储:Shared Preferences

    Android数据存储之SharedPreferences 在Android系统中提供了多种存储技术.通过这些存储技术可以将数据存储在各种存储介质上, Android 为数据存储提供了如下几种方式: ...

  7. android+默认存储,Android 数据存储之SP存储,内部存储,外部存储

    Android 数据存储之SP存储,内部存储,外部存储 Android提供了多种数据存储的技术来永久的保存应用数据,以便于开发者能够根据自己的需求来选择合适的数据存储方案,主要有SharedPrefe ...

  8. Android数据存储安全实践

    0x00 数据安全 Android操作系统自问世以来凭借其开放性和易用性成为当前智能手机的主流操作系统之一,作为与人们关系最密切的智能设备,越来越多的通讯录.短信.视频等隐私数据以明文的方式保存在手机 ...

  9. 【Android数据存储】ContentProvider详细介绍(附实例源码)

    1.ContentProvider是什么? ContentProvider--内容提供者.它是一个类,这个类主要是对Android系统中进行共享的数据进行包装,并提供了一组统一的访问接口供其他程序调用 ...

  10. Android数据存储和读取的三种方法

    Android数据存储和读取的三种方法 一.文件存储 二.Context存储 三.SharedPreferences存储 一.文件存储 1.利用文件进行数据的存储 public static bool ...

最新文章

  1. 在线直播 | 是事实还是贩卖焦虑?IT行业也偏爱“小鲜肉”​
  2. python简介怎么写-python爬虫简历怎么写
  3. GDCM:解析XPATH文件的测试程序
  4. thinking-in-java(20)注解
  5. 直接学python3_学习python用python2还是python3
  6. Java json拼接字符串_Java中拼接json格式字符串
  7. Ubuntu 挂载磁盘
  8. react axios封装
  9. 威联通(NAS)搭建个人音乐中心
  10. 如何快速统计Excel单元格中有几个数字
  11. Android手机APP广告植入与产品上线
  12. ICLR22 自监督graph learning------------AUTOMATED SELF-SUPERVISED LEARNING FORGRAPHS--- 密歇根州立
  13. samba共享使用端口
  14. 基于51单片机的关于7SEG-MPX8-CA,7SEG-MPX6-CA,7SEG-MPX4-CA的使用
  15. 一次 BO 报表引发的数据库宕机要点分析
  16. JavaScript小技能:客户端 API
  17. 八一钢铁:宝钢入主,中报业绩大幅增长
  18. 王慧文清华产品课(三)
  19. 遨博机器人执行线程_遨博机器人报错代码:If命令 if…else和条件选择命令Switch...Case...Default...
  20. implicitlyWait和explicitlyWait的秘密

热门文章

  1. 小程序仿照抖音点赞功能
  2. 为什么别人的抖音那么多赞,抖音怎么提升点赞
  3. 基于java所写的学生选课管理系统
  4. React map循环
  5. Web后端框架Springboot创建和基础讲解(一)
  6. js获取当前域名、Url、相对路径和参数
  7. 梳理 BERT和BERT变种
  8. 劳动合同法之试用期工资的算法(轉)
  9. iOS开发:图片加载@2x与@3x
  10. 如何通过纠正店铺标签来优化搜索权重?多角度解析手淘搜索