企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持知识库和私有化部署方案 广告
[TOC] #[Android]数据存储-文件存储 ##参考 [彻底理解android中的内部存储与外部存储] [Android Training-保存文件] ##简介 作为 Android 开发学习的新手,最近有学习涉及“下载文件”的功能,所以渐渐接触了 Android 文件存储的概念。<br/> 刚开始看相关资料的时候,我就有非常多的疑问: * 我应该把下载的文件保存在哪里,如何获得相应的路径? * Android 手机系统中可以看到非常多的文件夹,里面都放了什么? * [Environment] 和 [Context] 中提供了很多用于获取路径的方法,到底代表了哪些路径? * 等等............ 本篇文章主要参考网上写得比较全面的文章和 Android 官方文档的说明。如果你和我刚开始一样,也没有学习过这方面的内容,不妨阅读一下,相信会有一些收获。 **本文示例的代码偏简单,扩展可以参考官方文档,也推荐自己动手验证其中没有用代码证明的观点** ##查看手机文件的方法 先运行 Android studio 的 6.0 系统的虚拟机 然后通过:Tools------->Android------->Android Device Monitor ![文件查看](https://box.kancloud.cn/5cff6681c8cb2f19297c5088db60dd01_774x474.png) ![FileExplorer](https://box.kancloud.cn/68c610ed9030f44469ca7743e51a9471_376x132.png) 一般默认就会出现 FileExplorer 了。如果没有,可以在 Window 中的 ShowView 中调出来。 ##内部存储-InternalStorage 图中标识 1 的 "data" 文件夹就代表了我们所常说的内部存储。标识 2 的 "data" 文件夹下有一些以 App 包名命名的文件夹。 ![内部存储路径图](https://box.kancloud.cn/fbc2a73fb34eea2cfb8193098980dfdc_523x602.png) 打开 data/data 后,我们通常会看到这些名字的文件夹 : * cache 用于存储缓存文件 * code_cache 存储由运行时应用程序生成的编译或优化的代码,可参考Context.getCodeCacheDir() 方法说明 * shared_prefs 与 SharedPreferences 存储相关 * file 用于存储文件 * databases 与数据库存储相关 内部存储有以下几个特点: * **它始终可用**<br/> 与外部存储相比,内部存储在使用时无需判断状态是否可用(内部存储是内置的,而外部存储可能是存储卡,卡片可以被拔出或卸载,但内部存储一直可用),而且读写不需要申请权限 * **只有您的应用可以访问此处保存的文件**<br/> 用户和其他应用都无法直接访问这里的文件 * **当用户卸载您的应用时,系统会从内部存储中移除您的应用的所有文件**<br/> 如果卸载一个应用程序,那么 data/data/包名 的这个文件夹也会被删除掉 ##内部存储的示例 ~~~ 1.在 data/data/包名/files 文件夹下创建一个名为 123 的空文件 //调用 Context 中的 getFilesDir() 方法, 该路径就是 data/data/包名/files File file =new File(context.getFilesDir(),"123"); file.createNewFile() 2.在 data/data/包名/cache 文件夹下创建一个名为 123 的空文件 //与上个方法一致,只是路径改为 data/data/包名/cache File file =new File(context.getCacheDir(),"123"); file.createNewFile() ~~~ ## 外部存储-ExternalStorage ![外部存储路径图](https://box.kancloud.cn/88fe54f89d8471ac5b31530e34da78fc_611x262.png) 在 storage/0 这个目录下,还会分为 2 类目录: * 私有目录:Android/data/ 就是私有目录,不同的包名命名的文件夹即代表了不同的应用程序的私有目录。它和内部存储有些像,如果把文件存放在这里,那么就可以减轻内部存储的存储压力,因为外部存储的空间大小一般是要比内部存储的空间大小要大,但同时也会暴露给用户和其他应用程序。 * 公有目录:系统为我们创建的九大类文件夹,如果把数据存放在这里,那么其他应用程序也可以访问读取,有利于数据之间的共享。 1. DCIM 将设备作为相机安装时的图片和视频的传统位置(选择 USB 的连接方式时,如果选择传输照片模式,那么连接电脑的时候就会显示 DCIM 和 Pictures 文件夹) 2. Pictures 放置用户可用的图片的标准目录 3. Download 放置用户下载的文件的标准目录 4. Movies 放置用户可用的电影的标准目录 5. Music 放置任何音频文件的标准目录,该音频文件会出现在用户的常规音乐列表中 6. Podcasts 播客列表中的音频文件的标准目录 7. Notifications 通知列表中的音频文件的标准目录 8. Alarms闹钟列表中的音频文件的标准目录 9. Ringtones 铃声列表中的音频文件的标准目录 其中 5、6、7、8、9 都与音频文件有关,从字面上可以明白大概的作用,我们测试一下。 假设我们现在有一个音频文件,我们把它放到 Alarms 文件夹中。那么我们就可以在“声音”设置中设置该音频文件为闹铃了。虽然它也是音频文件,但是我们在“存储”设置中点击音频文件,或者设置手机的“铃声”是不显示这个文件的,所以其中起到的归类的作用我想你应该明白了。 ![放入音频文件到Alarms文件夹](https://box.kancloud.cn/1f5d5432a5378b33b9474ad705022d59_496x182.png) ![Android设置](https://box.kancloud.cn/7fb306dace289f7aac8e87dfa0050a00_503x728.png) ![设置闹钟铃声](https://box.kancloud.cn/b96d05c91bd21cbe1f75b6b4f14e3f7d_534x772.png) 外部存储有以下几个特点: * **它并非始终可用,因为用户可采用 USB 存储设备的形式装载外部存储,并在某些情况下会从设备中将其移除。**<br/> 如之前所提到,外部存储可能是通过 SD 卡实现的,那么如果卡被拔出,外部存储的状态也会变为不可用了,那么这时候再通过外部存储进行读写操作,肯定是不可以的。 * **它是全局可读的,因此此处保存的文件可能不受您控制地被读取。**<br/> 内部存储可以通过设置,阻止其他应用的访问。但是对于外部存储来说,公有目录的目的恰恰是与其他应用共享数据,或者让使用者在连接电脑时可以访问这些数据。私有目录的文件虽然也可以被访问,但是私有目录中的文件往往只对本应用程序有作用,所以即使其他应用程序可以访问,也没有什么意义。 * **当用户卸载您的应用时,只有在您通过 getExternalFilesDir() 将您的应用的文件保存在目录中时,系统才会从此处移除您的应用的文件。**<br/> 如果一个应用程序在运行中创建了文件保存在公有目录下,或者是公有目录中的九大类文件夹中,那么即使卸载该应用程序,这些文件也不会被删除。如果你在外部存储的私有目录中以包名创建的文件夹,那么卸载应用程序时,该文件夹也会被删除(只有是以包名命名的文件夹才会被系统清除,如果你创建一个名为 "包名+123" 的文件夹,那是不会被删除的) ##外部存储的示例 ~~~ 在使用外部存储之前,我们需要做 2 件事情 申请 WRITE_EXTERNAL_STORAGE 权限,因为该权限属于危险权限,需要使用申请运行时权限(代码略去) 判断外部存储是否可用 public boolean isExternalStorageWritable() { String state = Environment.getExternalStorageState(); if (Environment.MEDIA_MOUNTED.equals(state)) { return true; } return false; } 假设我们现在完成了这两步 1.在 storage/0/Android/data/包名/cache 下创建一个文件 new File(getExternalCacheDir(),"321").createNewFile(); // Android/data/包名 这个目录默认的不存在的 //如果我们的 Android/data/包名/cache 这个目录不存在,那么调用 File.createNewFile() 方法就会出错(不能在一个不存在的目录下创建文件) //所以当你调用 getExternalCacheDir() 方法时,它就会帮你创建好 包名/cache 这个文件夹 2.在 storage/0/Android/data/包名/files 下创建一个文件 new File(getExternalFilesDir(null),"123").createNewFile(); // getExternalFilesDir() 也是同样道理,而且它接受一个参数,参数可以传入 null 或者是之前提到的九类文件夹,如:Enviroment.DIRECTORY_PICTURES //如果传入除了 null 之外的参数,那么它就会在 files 文件夹中创建对应的文件夹,如:files/Pictures ,也可以起到分类的作用。 3.在公有目录 storage/0/Alarms 中创建一个文件 File file= new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "123.png"); file.createNewFile(); //上面的代码就是在 storage/0/Pictures 目录下创建了一个 123.png 文件,当然这个文件是空的。 //getExternalStoragePublicDirectory(String type) 其中的参数就是接收文件的类型, //如果传入 null ,即表示在 storage/0 目录下 ~~~ ##总结 参考的文章中有提到一个规律:有包名的路径我们都是调用Context中的方法来获得,没有包名的路径,我们直接调用 Environment中 的方法获得,可以方便我们记忆。 回到之前开头所提到的问题 * 如果外部存储可用,那么我们可以放在外部存储的私有目录中,如果不可用,那么我们只能存放在内部存储中,可以通过 [Context] 提供的方法得到路径。 * Android 存储始终分为内部存储和外部存储,根据文件夹的名称是可以大概判断它的作用的。 * 根据刚才所说的规律以及查询 Api 文档,随着使用次数的增加,相信你会更加熟悉。 这个问题是从别的文章中看到的,我觉得也很有意义:当你对一个 App 执行“清除数据”和“清除缓存”的操作时,分别清除了哪些数据? ![清除数据和清除缓存](https://box.kancloud.cn/eab45365d8a14e9a500ad0afd01ac76f_637x553.png) * 清除缓存:清空内部存储的 cache 文件夹,删除外部存储中的私有目录中的 cache 文件夹。 * 清除数据:删除外部存储的私有目录的包名文件夹,清空内部存储中的包名文件夹 至于放在外部存储的公有目录下的文件嘛,你就放心吧,连卸载应用程序都删除不了它们,清除数据当然也不会影响到它们啦。 如果你之前没有了解过 Android 中的文件存储的知识,希望可以通过这个文章来帮你形成一个基本的概念,在碰到一些相关代码时,可以理解其中的意思,再通过阅读其他资料加深理解。如果想要学习更多关于这方面的内容,当然是[Android文档]啦! [Android文档]:https://developer.android.google.cn/index.html [Context]:https://developer.android.google.cn/reference/android/content/Context.html [Environment]:https://developer.android.google.cn/reference/android/os/Environment.html [彻底理解android中的内部存储与外部存储]:http://blog.csdn.net/u012702547/article/details/50269639 [Android Training-保存文件]:https://developer.android.google.cn/training/basics/data-storage/files.html