Android 数据存储(一)-文件存储

2023-05-16

目录

一、数据存储概念

二、应用程序专属文件存储

2.1 访问持久文件

2.2 将数据存储到文件

2.3 从文件中读取数据

2.4 查看文件列表

2.5 删除文件

三、缓存文件(cache目录下)

3.1 创建缓存文件

3.2 删除文件

四、外部存储

五、共享文件存储

项目地址


一、数据存储概念

Android系统提供了提供了多种保存应用数据的选项:

  • 文件存储
    • 应用程序专属文件存储:
      • 内部存储(保存其他应用不应访问的敏感信息)

      • 外部存储

    • 共享文件存储:存储你的应用打算与其他应用共享的文件,包括媒体、文档和其他文件。

  • Preferences:默认情况下,Preferences 使用 SharedPreferences 来保存值。

  • 数据库:使用 Room 持久性库将结构化数据存储在私有数据库中。

        瞬时数据:是指那些存储在内存当中,有可能会因为程序关闭或其他原因导致内存被回收而丢失的数据。

        数据持久化:是指将那些内存中的瞬时数据保存到存储设备中,保证即使在手机或电脑关机的情况下,这些数据仍然不会丢失。持久化技术则提供了一种机制可以让数据在顺势状态和持久状态之间进行转换。

二、应用程序专属文件存储

        文件存储是Android中最基本的一种数据存储方式,它不对存储的内容进行任何的格式化处理,所有数据都是原封不动地保存到文件当中的,因而它比较适合用于存储一些简单的文本数据或二进制数据

访问方法

  • 内部存储(Internal Storage),

    • getFilesDir()

    • getCacheDir()

  • 外部存储(External Storage)

    • getExternalFilesDir()

    • getExternalCacheDir()

注意:卸载应用时,所以目录下的文件将被移除。并且其他应用无法访问这些专属文件。

所需权限:

  • 内部存储永远不需要

  • 当你的应用在运行 Android 4.4(API 级别 >=19)时,外部存储不需要(目前应用兼容基本5.0起步了)。

2.1 访问持久文件

        你可以使用Context对象的 filesDir 属性访问该目录。

        //From internal storage, getFilesDir() or getCacheDir()
        File filesDir = getFilesDir();//持久文件目录
        //FilesDir:/data/user/0/com.scc.datastorage/files
        Log.e("File","FilesDir:"+filesDir.getAbsolutePath());
        File cacheDir = getCacheDir();//缓存文件目录
        //CacheDir:/data/user/0/com.scc.datastorage/cache
        Log.e("File","CacheDir:"+cacheDir.getAbsolutePath());

        com.scc.datastorage:代表你的包名。

注意:为帮助保持应用程序的性能,请勿多次打开和关闭同一个文件。

2.2 将数据存储到文件

        Context类中提供了一个openFileOutput()方法,可以用于将数据存储到指定的文本中。

这个方法接受两个参数:

  • 第一个参数是文件名,在文本创建的时候使用的就是这个名称,注意这里指定的文件名不可以包含路径(因为默认存储到/data/data/<packagename>/files/目录下)。

  • 第二个参数是文件的操作模式,主要有两种:

    1. MODE_PRIVATE:默认的操作模式,表示当指定同样文件名的时候,当该文件名有内容时,再次调用会覆盖原内容。

    1. MODE_APPEND:表示该文件如果已存在就往文件里面追加内容。

        调用 openFileOutput() 来获取 FileOutputStream,得到这个对象后就可以使用Java流的方式将数据写入到文件中了。

    public void write(){
        //文件名
        String filename = "sccFile";
        //写入内容(shuaici)
        String fileContents = fileStorageBinding.etInput.getText().toString();
        //内容不能为空
        if (fileContents.isEmpty()) {
            Log.e("File","FileContents.isEmpty()");
            return;
        }
        BufferedWriter writer = null;
        try  {
            //获取FileOutputStream对象
            FileOutputStream fos = openFileOutput(filename, Context.MODE_PRIVATE);
            //通过OutputStreamWriter构建出一个BufferedWriter对象
            writer = new BufferedWriter(new OutputStreamWriter(fos));
            //通过BufferedWriter对象将文本内容写入到文件中
            writer.write(fileContents);
        }catch (IOException e){
            Log.e("File",e.getMessage());
        }finally {
            try {
                //不管是否抛异常,都手动关闭输入流
                if(writer != null) writer.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

        如果你想在同一个文件写入多个内容那么需要将第二个参数改为MODE_APPEND

out = openFileOutput("data", Context.MODE_PRIVATE);

        存储了3次内容(ANDROID、shuaici、123456)如下:

2.3 从文件中读取数据

    //读取文件
    public void read(){
        Log.e("File","read.start");
        String filename = "sccFile";
        BufferedReader reader = null;
        try  {
            //获取FileInputStream对象
            FileInputStream fis = openFileInput(filename);
            //通过InputStreamReader构建出一个BufferedReader对象
            reader = new BufferedReader(new InputStreamReader(fis));
            StringBuilder sb = new StringBuilder();
            String line = "";
            //一行一行的读取,当数据为空时结束循环
            while ((line=reader.readLine())!=null){
                sb.append(line);//将数据添加到StringBuilder
            }
            Log.e("File",sb.toString());
            fileStorageBinding.etInput.setText(sb.toString());
        }catch (IOException e){
            Log.e("File",e.getMessage());
        }finally {
            Log.e("File","read.finally");
            try {
                if(reader != null) reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

注意:如果你需要在安装时以流的形式访问文件,请将文件保存在项目的 /res/raw 目录中。 你可以使用 openRawResource() 打开这些文件,传入以 R.raw 为前缀的文件名作为资源 ID。此方法返回一个可用于读取文件的 InputStream。你无法写入原始文件

2.4 查看文件列表

你可以通过调用 fileList() 获取包含 filesDir 目录中所有文件名称的数组,如下:

    //查看文件列表
    public void filelist(){
        String [] files = fileList();
        for (String file : files) {
            Log.e("File","FileList:"+file);
        }
    }

2.5 删除文件

  • 删除文件最简单的方法是让打开的文件引用本身调用delete()。

  • 如果文件保存在内部存储中,你还可以通过调用deleteFile()删除文件。

    //删除文件
    public void delete(){
        String filename = fileStorageBinding.etInput.getText().toString();
        Log.e("File","Delete:"+deleteFile(filename));
        filelist();
    }

注意:当用户卸载你的应用程序时,Android系统会删除保存在内部存储和外部存储中的所有文件。 当然你也可以定期删除你所创建的不需要的缓存文件。

三、缓存文件(cache目录下)

3.1 创建缓存文件

        如果你只需要临时存储敏感数据,你应该使用应用程序在内部存储中指定的缓存目录来保存数据。与files目录下存储一样,存储在此目录中的文件会在用户卸载你的应用程序时被删除

注意:

此缓存目录旨在存储你应用的少量敏感数据。

当设备内部存储空间不足时,Android 可能会删除这些缓存文件以恢复空间。因此,在读取缓存文件之前检查它们是否存在。

    //创建缓存文件
    private void createCache() {
        try {
            //方法一
            File timpfile = File.createTempFile("scc2022", ".txt", this.getCacheDir());
            Log.e("File","是否存在:"+timpfile.exists());
            Log.e("File","timpfile:"+timpfile.getAbsolutePath());
        } catch (IOException e) {
            e.printStackTrace();
        }
        //方法二:创建文件失败
        File file = new File(this.getCacheDir(), "file2022");
        Log.e("File","是否存在:"+file.exists());
        Log.e("File","file:"+file.getAbsolutePath());
    }

        方法一和方法二都会在应用程序缓存目录中添加文件,但是这里我用方法二创建文件始终不成功,方法二后面找找原因。这里重点介绍方法一。

  • 第一个参数prefix:文件名前缀

  • 第二个参数suffix:文件名后缀(如果不设置,默认.tmp)

  • 第三个参数directory:文件存放目录

        如上图不管是否指定后缀都会在文件名末尾添加一个随机数,以保持文件的唯一性。如上面文件名设置的为:scc2022.txt,但是创建出来的是:scc2022784042118208981946.txt。

        由于末尾添加一个随机数给删除或读取文件带来麻烦,所以可能需要调用file.getName()进行文件名存储。否则不好找。如此下来其实我更喜欢第二种方式,但是不知道什么情况创建不成功这就比较尴尬了。

3.2 删除文件

        尽管 Android 系统有时会自行删除缓存文件,但你可以自己删除数据。

    //删除缓存文件
    private void deleteCache() {
        //scc20221181329566644563700891.tmp和scc2022118都存在
        //但是cache目录下没有,咱们调用删除试试
        File cacheFile = new File(getCacheDir(), "scc20221181329566644563700891.tmp");
        //判断文件是否存在
        if(cacheFile.exists())
        {
            //使用File对象的delete()方法
            Log.e("File","delete17:"+cacheFile.delete());
        }
        
        File cacheFile2 = new File(getCacheDir(), "scc2022118");
        if(cacheFile2.exists())
        {
            //应用Context的deleteFile()方法
            Log.e("File","deleteFile19:"+deleteFile("scc2022118"));
        }
    }

四、外部存储

如果内部存储太小无法提供更大的空间那么可以使用外部存储

  • 外部存储(External Storage)
    • getExternalFilesDir()//持久文件

    • getExternalCacheDir()//缓存文件

        在 Android 4.4(API 级别 >=19),你的应用无需请求任何与存储相关的权限即可访问外部存储中的应用特定目录。当你的应用程序被卸载时,存储在这些目录中的文件将被删除。

注意:

1、不能保证文件可以访问,因为可能SD卡被移除。

2、在 Android 11(API 级别 >=30),应用无法在外部存储上创建自己的应用特定目录。感觉外部存储还是少用。

验证存储是否可用

// 检查外部存储是否可用于读写。
private boolean isExternalStorageWritable() {
    return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
}

// 检查外部存储至少可读。
private boolean isExternalStorageReadable() {
     return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) ||
            Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED_READ_ONLY);
}

五、共享文件存储

以前写过一篇,感兴趣的可以去看看:

https://shuaici.blog.csdn.net/article/details/116942978icon-default.png?t=LBL2https://shuaici.blog.csdn.net/article/details/116942978

项目地址

Android 数据全方案处理

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android 数据存储(一)-文件存储 的相关文章

  • 在 Android 10/Q 上运行的 Android ACTIVITY_RECOGNITION 权限 SDK 28 (SDK 29)

    我的 Android 应用程序以 SDK 28 为目标 并连接到 Google Fit 以上传数据并读取其他一些数据 该应用程序使用 HistoryAPI 读取 com google step count delta 数据 本文档声称 如果
  • 支持 API 28(Android Pie) 上的 Android StrongBox 的 Android 智能手机列表

    我需要 Android 9 中支持安全元件和 StrongBox 的 Android 手机列表 在哪里或如何找到该列表 我在 Samsung Galaxy S9 和 AVD Google Pixel XL API 28 上尝试了下面的代码
  • onScale 和 Canvas - 缩放图像后如何调整原点?

    我有一个非常简单的测试应用程序 带有自定义组件MyView java https github com afarber android newbie blob master TestScroll src de afarber testscr
  • 小米设备正在停止前台服务

    我们有一个几乎永远运行的应用程序前台服务 同时使用系统托盘上的通知 这是正常的初始化 该应用程序仅依赖于此服务 在我们测试的每台设备上 即使任务被删除 服务也会继续运行 但在小米设备上 从最近的任务滑动后 它突然停止 然后再次启动 具体取决
  • 如何解决 FireBase 数据库 Key 中的禁止字符或解决方法

    我有这个 FireBase 数据库结构 我真的很想拥有像这个例子这样的密钥 US name United States PATH TO STREETS US California Orange County Orange 3138 E Ma
  • 如何修复第三方 SDK 中重复的 libgnustl_shared.so 文件?

    当我使用 gradle 构建并运行 apk 时 出现以下错误 Error Execution failed for task app transformNative libsWithMergeJniLibsForDebug gt com a
  • 实施材质主题时遇到问题

    我在用this http antonioleiva com material design everywhere 作为在 Android 5 0 之前的设备上向现有应用程序实施 Material 主题的教程 我的问题是我得到了Null Po
  • 删除对象时删除嵌套字段中的索引

    我仍在使用 Firebase 这次我有一个与删除对象相关的问题 我有如下结构 users UsErId1 name Jack email email protected cdn cgi l email protection UsErId2
  • Android 设备选择器在目标列中显示红色 X

    我最近构建了一个 Android 应用程序 minSdkVersion 为 7 targetSdkVersion 为 10 我现在正在使应用程序兼容平板电脑并添加操作栏 因此 我将 targetSdkVersion 更新为 15 并在项目属
  • 当 Android 上的脸部靠近屏幕时,以编程方式关闭屏幕

    我的应用程序是一个拨号器 当用户将手机靠近头部时 我需要关闭屏幕并防止单击控件 就像本机 Android 拨号器行为一样 我需要什么 API 级别以及如何以正确的方式做到这一点 我通过反汇编一个非常著名的 VoIP 应用程序找到了解决方案
  • 从 JSON 数组创建标记 php mySQL Google Maps v2 android

    我正在尝试从 mySQL 数据库在 Google Maps v2 上创建标记 但它不起作用 地图确实出现了 但没有标记 谁能告诉我出了什么问题以及我需要改变什么 我也尝试过让 getDouble 为 getDouble 0 和 getDou
  • Android 生命周期哪个事件在生命周期中只触发一次?

    我读过一些博客并访问了一些网站 我想知道哪个事件在生命周期中只触发了一次 阅读博客后我意识到onCreate 方法在生命周期内仅触发一次 我不知道我是对还是错 现在我的问题是 我想触发任何仅在我更改横向或纵向方向时触发一次的事件 而不是在启
  • 在 Android 运行时更改和应用主题 [重复]

    这个问题在这里已经有答案了 可能的重复 如何在 Android 运行时更改当前主题 https stackoverflow com questions 2482848 how to change current theme at runti
  • Android wifi的信号强度[重复]

    这个问题在这里已经有答案了 可能的重复 Android 如何监控WiFi信号强度 https stackoverflow com questions 1206891 android how to monitor wifi signal st
  • 如何为移动应用程序创建无密码登录

    我有兴趣在移动应用程序和 API 之间构建某种无密码登录 假设我可以控制两者 动机是必须登录对用户来说非常烦人并且存在安全风险 例如 用户将重复使用现有密码 我希望用户能够立即开始使用该应用程序 我想知道是否有一些可行的技术 例如 在移动设
  • Android 4.2以下如何设置layoutDirection为RTL

    尝试将布局元素设置为 RTL 顺序 4 2 及以上行 layoutDirection rtl 并在清单中 android supportsRtl true 工作得很好 但对于 4 2 以下则不然 解决方案有人吗 只需使用视图兼容使用 and
  • 无法获取 android.permission.CLEAR_APP_USER_DATA

    我正在开发需要特殊权限的系统应用程序 由于某种原因 我无法获得 CLEAR APP USER DATA 权限 但我可以使用 INSTALL PACKAGES DELETE PACKAGES 等 什么可能导致这种情况 显现 uses perm
  • 数字时钟不改变时间

    我正在开发一个数字时钟小部件 我写了代码 但它没有更新时间 我没有使用任何服务并在模拟器中运行 我的代码如下 public class ExampleAppWidgetProvider extends AppWidgetProvider D
  • 如何调试仅在发布模式下崩溃的 Android 应用程序

    在调试模式下一切正常 但在发布模式下崩溃 调试模式下有哪些所需权限在发布模式下未打开 EDIT 当我将 链接 设置为 无 时 我会通过第一个屏幕进入 登录 屏幕 但是 当我添加发布权限时Internet 第一次尝试读取远程实体框架核心表时它
  • 新的 Android 项目未创建布局或 Java 文件

    这两天我一直在尝试简单地阅读 Big Nerd Ranch Android 编程书 第一章的前几页 我的问题的要点是 当我创建新的 Android 应用程序时 不会创建布局或 java 文件 我已经从 Android 开发站点安装了 ADT

随机推荐

  • Trinity简介(1)--用于无参考基因组的转录组de novo组装

    一 Trinity简介 Trinity xff0c 是由 the Broad Institute 开发的转录组de novo组装软件 xff0c 由三个独立的软件模块组成 xff1a Inchworm Chrysalis和Butterfly
  • Trinity进行转录组组装(2))

    1 Trinity进行转录组组装 Trinity进行转录组组装的典型命令如下 opt biosoft trinityrnaseq r20131110 Trinity pl seqType fq JM 50G left sample1 1 c
  • python的两种退出方式

    os exit vs sys exit 转自 xff1a http www cnblogs com gaott archive 2013 04 12 3016355 html 概述 python的程序有两种退出方式 xff1a os exi
  • R语言数据类型转化

    R语言数据类型转化 转自 xff1a http www wangluqing com 2014 09 10 r share34 有时候 xff0c 对于一些问题 xff0c 需要进行数据类型之间的转换 R提供了基本类型转换函数以解决数据类型
  • ubuntu20.04安装中文输入法

    虽然搜狗的官网已经宣传说已经支持2004 2010 xff0c 但是支持的并不完美 xff0c 闪退 xff0c 打不出字各种问题不断 xff0c 所以本文带领大家安装几款能够正常使用的中文输入法 但是正在我要发这篇博客的时候 xff0c
  • R语言做柱状图

    R语言做柱状图 转自 xff1a http www phperz com article 16 0102 180120 html 条形图代表在与条成比例的变量的值的长度矩形条数据 R使用函数barplot 来创建柱状图 R能够绘制柱状图垂直
  • R语言 PCA(主成分分析)

    R语言 PCA 转自 xff1a http www cnblogs com longzhongren p 4300593 html 1 关键点 综述 xff1a 主成分分析 因子分析 典型相关分析 xff0c 三种方法的共同点主要是用来对数
  • 使用Pandas对数据进行筛选和排序

    使用Pandas对数据进行筛选和排序 转自 xff1a http bluewhale cc 2016 08 06 use pandas filter and sort html 筛选和排序是Excel中使用频率最多的功能 xff0c 通过这
  • linux 下安装blat软件

    linux 下安装blat软件 blat是一款很经典的比对工具 xff0c 与blast相比 xff0c 具有速度快 共线性输出比对结果等优点 但是 xff0c blat源码包里面的README文件写得很不清楚 xff0c 这里 xff0c
  • 基于统计的压缩算法:游程编码

    原网址 xff1a http www cnblogs com xudong bupt p 3761417 html 基于统计的压缩算法 xff1a 游程编码 1 游程编码概念 游程编码又称 运行长度编码 或 行程编码 xff0c 是一种统计
  • BWT (Burrows–Wheeler_transform)数据转换算法

    原网址 xff1a https blog csdn net luanzheng 365 article details 78575429 BWT Burrows Wheeler transform 数据转换算法 1 什么是BWT 压缩技术主
  • pip使用豆瓣的镜像源

    抄自 xff1a https www cnblogs com ZhangRuoXu p 6370107 html pip使用豆瓣的镜像源 豆瓣镜像地址 xff1a https pypi douban com simple 虽然用easy i
  • PyVCF

    抄自 xff1a https www cnblogs com nkwy2012 p 9204088 html vcf文件的全称是variant call file xff0c 即突变识别文件 xff0c 它是基因组工作流程中产生的一种文件
  • 【Kotlin 初学者】扩展-享受编程

    作者简介 xff1a CSDN博客专家 华为云 云享专家认证 系列专栏 xff1a Kotlin 初学者 学习交流 xff1a 三人行必有我师焉 xff1b 择其善者而从之 xff0c 其不善者而改之 目录 一 介绍 二 扩展函数 2 1
  • 【Kotlin 初学者】函数式编程

    作者简介 xff1a CSDN博客专家 华为云 云享专家认证 系列专栏 xff1a Kotlin 初学者 五星好评 xff1a 左侧点一下 网页端 xff0c 移动端 xff1a https bbs csdn net topics 6039
  • centos8.5 更新失败

    今天使用yum makecache的时候出现了Error Failed to download metadata for repo 39 base 39 Cannot download repomd xml Cannot download
  • 【Kotlin 初学者】Java和Kotlin互操作

    作者简介 xff1a CSDN博客专家 华为云 云享专家认证 系列专栏 xff1a Kotlin 初学者 五星好评 xff1a 左侧点一下 网页端 xff0c 移动端 xff1a https bbs csdn net topics 6039
  • Kotlin 基础知识汇总(知识与实践相结合)

    2个月的时间总算把 Kotlin 的基础知识写完了 xff0c 下面咱们看看具体内容 xff1a 学习 Kotlin 的必要性 Kotlin 初学者 为什么要学Kotlin Kotlin 初学者 打牢基础的重要性 运行环境 Kotlin 初
  • HashMap的产生与原理

    一 HashMap的诞生 1 1 数组 数组 xff1a 一片物理上连续的大小确定的储存空间 好处 xff1a 根据下标快速的查找和修改里面的内容 缺点 xff1a 大小确定 xff0c 无法修改 添加新的元素或者删除元素比较麻烦 数组的静
  • Android 数据存储(一)-文件存储

    目录 一 数据存储概念 二 应用程序专属文件存储 2 1 访问持久文件 2 2 将数据存储到文件 2 3 从文件中读取数据 2 4 查看文件列表 2 5 删除文件 三 缓存文件 cache目录下 3 1 创建缓存文件 3 2 删除文件 四