应用中关于数据的持久化保存,不管是简单的SharedPreferences还是数据库SQLiteDatabase,本质上都是将数据保存到系统的某种类型的文件中。因此可以直接使用java.io.File文件类将数据以任意类型存取。

在获取到File文件类的对象后,就可以使用其相关方法执行对文件的读写等相关操作,这部分属于Java语言开发或Kotlin语言开发的基础知识,不再多言。而在Android系统上因为各种原因,获取File对象的方式有所区别,本文将重点介绍。

这里需要注意,File文件类不仅可以是一个可读写数据的正常文件,也可以是一个包含上述文件的文件夹。下文如无特别说明,文件亦指保存数据的正常文件和包含正常文件的文件夹。

硬件存储区域

在了解数据的文件存储之前,当然要先搞清楚Android系统对硬件存储设备的划分规则。

一般设备所安装Android系统的分区空间,被定义为Android系统的内部存储空间。通常应用程序的安装包及安装后的相关数据文件,都默认保存在内部存储空间中。内部存储空间为不同应用程序划分了不同的访问区间可以操作,而系统用户是无法正常访问内部存储空间的,这有效防止了应用程序间的文件安全性。

内部存储的空间往往不会太大,因此不建议应用程序在内部存储中占用大量空间。于是Android系统又定义了外部存储空间,应用程序过大的文件可存储在外部存储中,比如相机应用程序所保存的照片。同时外部存储是允许系统用户访问的,这也就是文件管理应用程序所展示的存储空间。

而在某些硬件设备中,比如较老版本的移动手机,为了增大硬件存储空间,还会使用SDcard增加可扩展存储区。这部分存储同样属于系统的外部存储空间范畴。

在访问外部存储时,应用程序需要申请外部存储的读写权限,包括android.Manifest.permission.READ_EXTERNAL_STORAGEandroid.Manifest.permission.WRITE_EXTERNAL_STORAGE

系统级文件

所谓系统级文件,就是该类文件允许系统中的任何应用程序读写访问。其中外部存储空间中的文件都是系统级文件。

目标版本级别小于29的应用程序

在Android10即API 29以前,手机的外置SD卡可以作为系统级文件使用,在应用程序中,可以借助android.os.Environment环境类的getExternalStorageDirectory()系列静态方法获取外部存储中的相关File文件,同时使用isExternalStorageEmulated ()系列静态方法获取类似外部存储是否加载等信息。

这里获取外部存储根目录的Environment.getExternalStorageDirectory()方法在API29中废弃,而在API30中替换为Environment.getStorageDirectory()方法。

目标版本级别等于29的应用程序

从Android10开始,系统引入了分区存储的概念,在开启了分区存储的应用程序中,只能访问其应用级文件和媒体文件。应用级文件在下文会有详细讲解。而所谓的媒体文件是保存在外部存储中的,主要包括图片、音频、视频和下载文件,共四种媒体文件类。

其中一般图片存储路径为 DCIM/Picture/ ,并将文件信息存储在MediaStore.Images类定义的相关常量所标记的数据库中;

音频存储路径为 Alarms/Audiobooks/Music/Notifications/Podcasts/Ringtones/ ,并将文件信息存储在MediaStore.Audio类定义的相关常量所标记的数据库中;

视频存储路径为 DCIM/Movies/Picture/ ,并将文件信息存储在MediaStore.Video类定义的相关常量所标记的数据库中;

下载文件存储路径为 Download/ ,并将文件信息存储在MediaStore.Downloads类定义的相关常量所标记的数据库中。

这里的下载文件路径MediaStore.Downloads需要特别注意,其路径只适用于Android10即API 29及以上的系统上,不管应用程序的目标版本级别为多少,只要在Android9及以下版本中,就无法访问下载文件路径的相关内容。

而且在下载文件路径中的文件,如果由非创建该文件的应用程序所访问,只能使用存储访问框架调用系统文件选择器与用户交互,而不能像另外三种媒体文件一样直接代码访问。

分区存储的开启方式是修改 AndroidManifest.xml 清单文件,在 <application> 标签中增加属性值内容 android:requestLegacyExternalStorage=“false”,这也是默认设置;反之,如果设置android:requestLegacyExternalStorage=“true”则是关闭分区存储,官方推荐该配置仅可在文件兼容性适配阶段作为过渡使用。

开启了分区存储的应用程序,在读写自己的应用级文件时,不需要另外申请权限。但是在访问媒体文件时,同样需要外部存储的读写权限,包括android.Manifest.permission.READ_EXTERNAL_STORAGEandroid.Manifest.permission.WRITE_EXTERNAL_STORAGE

而媒体文件的访问方式,是通过上下文环境Context对象的getContentResolver()方法,获取android.content.ContentResolver内容解析类对象,通过该对象可以对Android系统的数据库进行增删改查等操作,其用到的相关常量都可以在上文的四种媒体文件类中查询。至于ContentResolver内容解析类的原理和使用方式,将在后面关于应用级文件共享的文章中详细讲解。

目标版本级别不小于30的应用程序

在Android11及API 30及以上的系统中,强制开启了分区存储,应用只能访问其应用级文件和媒体文件。同时新增了管理外部存储的权限android.Manifest.permission.MANAGE_EXTERNAL_STORAGE,与上文的外部存储的读写权限共同授权,允许当前应用程序访问外部存储的所有文件。

而访问外部存储的方式同样是使用Environment环境类的getStorageDirectory()系列静态方法获取外部存储中的相关File文件。

应用级文件

所谓应用级文件,就是该文件只运行其所属的应用程序读写访问,只能由该应用程序创建,且随着应用程序的卸载或清除数据而删除。

在没有开启分区存储之前,即Android 10系统版本之前,应用级文件不仅可以保存在内部存储中,也可以保存在外部存储中,且由于应用程序之间对外部存储的访问并未受到限制,所以外部存储部分的应用级文件往往可以被不同应用程序访问。

而自Android 10启用分区存储之后,应用程序的应用级文件只能保存在内部存储中,即便在Android 11系统之后恢复了应用程序对外部存储的访问授权,也不会在外部存储中创建应用级文件。

访问应用级文件的方式是通过上下文环境类

android.content.Context对象。

调用Context对象的getDir(String name, int mode)方法可以获取指定目录下的私有文件,返回File文件类型的对象,通常路径为 /data/data/应用包名/app_name/name。其中参数 name 是指定的文件名;参数 mode 是对该文件的操作模式,通常为Context.MODE_PRIVATE=0表示文件私有,或者Context.MODE_APPEND为写入文件的追加模式。

调用Context对象的getCacheDir()方法可以获取当前应用程序下的缓存文件目录,返回File文件类型的对象,通常路径为 /data/data/应用包名/cache/。

调用Context对象的getFilesDir()方法可以获取当前应用程序下的特定文件目录,返回File文件类型的对象,通常路径为 /data/data/应用包名/files/。

还有其他相关方法,可以获取当前应用程序下的某些指定文件目录,不再赘述。


对于应用程序下的应用级文件通常是不允许其他应用访问的,可如果某些应用级文件的确想被其他应用程序所访问,比如某个通讯类应用程序需要访问通讯录应用中的联系人信息,有什么好的办法呢?敬请关注下一章了解详情。

Android系统编程入门系列之应用数据文件化保存的更多相关文章

  1. Android系统编程入门系列之应用级文件在应用程序间的共享

    在上篇文章了解到应用级文件只能被其所创建的应用程序所访问,那么其他应用程序是不是就无论如何都无法访问了呢?肯定不是的,只要文件经过其创建的应用程序授权,还是可以被其他应用程序所访问的.这也就是应用级文 ...

  2. Android系统编程入门系列之加载界面Activity

    上回说到应用初始化加载及其生命周期,在Android系统调用Applicaiton.onCreate()之后,继续创建并加载清单文件中注册的首个界面即主Activity,也可称之为入口界面.主Acti ...

  3. Android系统编程入门系列之应用内键值对数据的简单保存

    在应用程序间及与用户的通信交互过程中,会产生并传递一系列数据.针对这些数据,有部分是只在应用程序中使用的缓存数据,还有一部分是在不同位置多次或长时间使用的持久化数据. 对于缓存数据来说,通常以代码中定 ...

  4. Android系统编程入门系列之应用内数据保存数据库

    上篇文章已经介绍了如何使用SharedPreferences存储键值对形式的轻量级数据,对于那些相同结构的多组数据,类似于存储Java中定义的类的多个对象属性值,如果按照键值对的形式一条条读写,需要分 ...

  5. Android系统编程入门系列之应用环境及开发环境介绍

        作为移动端操作系统,目前最新的Android 11.0已经发展的比较完善了,现在也到了系统的整理一番的时间,接下来的系列文章将以Android开发者为中心,争取用归纳总结的态度对初级入门者所应 ...

  6. Android系统编程入门系列之硬件交互——多媒体摄像头

    多媒体系列硬件 多媒体包括图片.动画.音频.视频,这些多媒体素材的采集(输入)主要依靠摄像头和麦克风等硬件设备转化为基础数据,而他们的播放渲染(输出),则需要依靠具有相关功能的编解码软件.当然随着硬件 ...

  7. Android系统编程入门系列之界面Activity绘制展示

    上篇文章介绍了界面Activity的启动方式和生命周期,本篇将继续介绍在界面Activity中的内容是如何绘制展示给用户的. 在Android系统上运行新创建的界面Activtiy,给用户展示的是空白 ...

  8. Android系统编程入门系列之界面Activity交互响应

    在上篇文章中已经了解到界面Activity的绘制完全依赖其加载的视图组件View,不仅如此,用户的每次触摸操作都可以在界面Activity内接收并响应,也可以直接传递给其中的某个视图View响应.本文 ...

  9. Android系统编程入门系列之界面Activity响应丝滑的传统动画

    上篇文章介绍了应用程序内对用户操作响应的相关方法位置,简单的响应逻辑可以是从一个界面Activity跳转到另一个界面Activity,也可以是某些视图View的相对变化.然而不管是启动一个界面执行新界 ...

随机推荐

  1. Create Shortcut to Get Jar File Meta Information

    You have to get meta information of cobertura.jar with command "unzip -q -c cobertura.jar META- ...

  2. 如何保证前端项目上线后的安全?webfunny已总结前端最关键的12大指标

    实时监控大屏   众所周知:实时流量大屏,是用来监控前端项目上线质量的. 如大家所知,监控系统会监控线上应用的各项指标,如:错误.白屏.耗时等等,但是仔细一想,即使有这些监控,我们也不一定能够保证线上 ...

  3. 联合迭代器与生成器,enumerate() 内置函数真香!

    花下猫语:Python 中很多内置函数的作用都非常大,比如说 enumerate() 和 zip(),它们使得我们在作迭代操作时极为顺手.这是一篇很多年前的 PEP,提议在 Python 2.3 版本 ...

  4. 题解—P3000 [USACO10DEC]Cow Calisthenics G

    做这题之前最好学会 "树形 \(dp\) 求树的直径"这一前缀知识(虽然我会但是我还是没想出来) 几乎想到要求直径这道题也没什么问题了(这不是废话吗,为什么题面里给了"直 ...

  5. 如何快速排查发现redis的bigkey?4种方案一次性给到你!

    本篇文章将以redis的bigkey为主题进行技术展开,通过从认识redis的高性能,bigkey的危害.存在原因.4种解决方案,到模拟实战演练的介绍方式,来跟大家一起认识.探讨和学习redis. 先 ...

  6. C语言预处理编译链接各个阶段错误,分阶段的说一下

    C语言预处理编译链接各个阶段错误,分阶段的说一下 C语言预处理编译链接各个阶段错误,分阶段的说一下比如指针异常,数组下标越界什么的    我来答 1个回答 #热议# 你觉得这辈子有希望看到996消失 ...

  7. SpringCloud bootstrap.yml 和application.yml 加载原理

    Spring Cloud 官方文档:https://cloud.spring.io/spring-cloud-static/spring-cloud.html 一个Spring Cloud的操作是通过 ...

  8. 【C#】Enum,Int,String的互相转换 枚举转换

    Enum为枚举提供基类,其基础类型可以是除 Char 外的任何整型.如果没有显式声明基础类型,则使用 Int32.编程语言通常提供语法来声明由一组已命名的常数和它们的值组成的枚举. 注意:枚举类型的基 ...

  9. 第一章 Net 5.0 快速开发框架 YC.Boilerplate--框架介绍

    YC.Boilerplate 框架介绍 YC.Boilerplate 是一套快速开发框架,采用当下流行的前后端分离开发模式,前端 采用VUE.后端采用Net 5.0:框架实现了 多租户.动态webAp ...

  10. JOB状态与并发

    由于job每次被执行时都会创建一个新的实例, jobDetail实例时,要进行数据存储或者,特殊字段操作,需要每次schedul执行job时保留之前的数据, 那么就需要job在有状态下保持之前的数据信 ...