前言
前两天因为开发一个app更新的功能,我将从服务器下载的apk文件放在了内部存储目录(测试手机为小米,路径为:data/user/0/packagename/files)下面,然后安装的时候一直安装不了,提示解析包出错。后来查询发现,安装apk是调用了PackageInstaller,没有相关权限,这个无法获取内部路径,所以会安装不了。借机也复习了一遍Android下面存储相关的知识点,特来总结一番。
存储分类
对于Android存储目录,我总结成一张思维导图,如果有需要原图的,请在我的公众号后台回复 015 即可获取原图。上面这张图很清楚的展示了Android存储的目录,接下来我们详细分析每一个目录。
内部存储
内部存储位于系统中很特殊的一个位置,对于设备中每一个安装的 App,系统都会在 data/data/packagename/xxx 自动创建与之对应的文件夹。如果你想将文件存储于内部存储中,那么文件默认只能被你的应用访问到,且一个应用所创建的所有文件都在和应用包名相同的目录下。也就是说应用创建于内部存储的文件,与这个应用是关联起来的。当一个应用卸载之后,内部存储中的这些文件也被删除。对于这个内部目录,用户是无法访问的,除非获取root权限。
String fileDir = this.getFilesDir().getAbsolutePath();
String cacheDir = this.getCacheDir().getAbsolutePath();
复制代码
一般情况下,我们获取到的路径为data/data/packagename/xxx,小米手机下面打印出来的结果如下:
对于内部存储路径,我们一般通过以下两种方式获取,内部存储空间的获取都需要使用Context:
context.getFileDir()
对应内部存储的路径为: data/data/packagename/files,但是对于有的手机如:华为,小米等获取到的路径为:data/user/0/packagename/files
context.getCacheDir()
对应内部存储的路径为: data/data/packagename/cache,但是对于有的手机如:华为,小米等获取到的路径为:data/user/0/packagename/cache应用程序的缓存目录,该目录内的文件在设备内存不足时会优先被删除掉,所以存放在这里的文件是没有任何保障的,可能会随时丢掉。
外部存储
针对于外部存储比较容易混淆,因为在Android4.4以前,手机机身存储就叫内部存储,插入的SD卡就是外部存储,但是在Android4.4以后的话,就目前而言,现在的手机自带的存储就很大,现在Android10.0的话,有的手机能达到256G的存储,针对于这种情况,手机机身自带的存储也是外部存储,如果再插入SD卡的话也叫外部存储,因此对于外部存储分为两部分:SD卡和扩展卡内存
我们通过一段代码来获取手机的外部存储目录,我们用的测试手机是三星G4,带有插入SD卡的:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
File[] files = getExternalFilesDirs(Environment.MEDIA_MOUNTED);
for (File file : files) {
Log.e("file_dir", file.getAbsolutePath());
}
}
复制代码
对于以上代码,打印的结果如下:
打印出两行目录,第一行目录是机身自带的外部存储目录,目录结构为:/storage/emulated/0/Android/data/packagename/files 第二行是存储卡的目录结构,路径为:/storage/extSdCard/Android/data/packagename/files
扩展外部存储
此目录路径需要通过context来获取,同时在app卸载之后,这些文件也会被删除。类似于内部存储。
getExternalCacheDir()
对应外部存储路径:/storage/emulated/0/Android/data/packagename/cache
getExternalFilesDir(String type)
对应外部存储路径:/storage/emulated/0/Android/data/packagename/files
SD卡存储
SD卡里面的文件是可以被*访问,即文件的数据对其他应用或者用户来说都是可以访问的,当应用被卸载之后,其卸载前创建的文件仍然保留。
对于SD卡上面的文件路径需要通过Environment获取,同时在获取前需要判断SD的状态:
MEDIA_UNKNOWN SD卡未知
MEDIA_REMOVED SD卡移除
MEDIA_UNMOUNTED SD卡未安装
MEDIA_CHECKING SD卡检查中,刚装上SD卡时
MEDIA_NOFS SD卡为空白或正在使用不受支持的文件系统
MEDIA_MOUNTED SD卡安装
MEDIA_MOUNTED_READ_ONLY SD卡安装但是只读
MEDIA_SHARED SD卡共享
MEDIA_BAD_REMOVAL SD卡移除错误
MEDIA_UNMOUNTABLE 存在SD卡但是不能挂载,例如发生在介质损坏
String externalStorageState = Environment.getExternalStorageState();
if (externalStorageState.equals(Environment.MEDIA_MOUNTED)){
//sd卡已经安装,可以进行相关文件操作
}
复制代码
getExternalStorageDirectory()
对应外部存储路径:/storage/emulated/0
getExternalStoragePublicDirectory(String type)
获取外部存储的共享文件夹路径如:
DIRECTORY_MUSIC 音乐目录
DIRECTORY_PICTURES 图片目录
DIRECTORY_MOVIES 电影目录
DIRECTORY_DOWNLOADS 下载目录
DIRECTORY_DCIM 相机拍照或录像文件的存储目录
DIRECTORY_DOCUMENTS 文件文档目录
String externalStoragePublicDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getPath();
复制代码
以上便是获取相机DCIM目录,对应获取的路径为:/storage/emulated/0/DCIM。
系统存储目录
getRootDirectory()
对应获取系统分区根路径:/system
getDataDirectory()
对应获取用户数据目录路径:/data
getDownloadCacheDirectory()
对应获取用户缓存目录路径:/cache
相关概念区别
getFileDir()和getCacheDir()区别
这两个都位于内部存储目录/data/data/packagename/下面,位于同一级别,前者是file目录下面,后面是cache目录下。
getFileDir()和getExternalFilesDir(String type)区别
前者位于内部存储目录/data/data/packagename/file下面,后者位于外部存储目录/storage/emulated/0/Android/data/packagename/files下面,它们都存在于应用包名下面,也就是说属于app应用的,所以当app卸载后,它们也会被删除的。
对于前面提到的app下载升级功能,我们从服务器端下载的app需要放到外部存储目录下面,而不是内部存储目录,因为内部存储目录的空间很小。另外我也做了相关测试,如果将apk放到内部存储目录file下面的话,安装时会出现问题,提示解析包出错。
清除数据和清除缓存的区别
在app中有清除数据和清除缓存这两个概念,那么这两者分别清除的是什么目录下面的数据呢?
清除数据
清除数据清除的是保存在app中所有数据,就是上面提到的位于packagename下面的所有文件,包含内部存储(/data/data/packagename/)和外部存储(/storage/emulated/0/Android/data/packagename/)。当然除了SD卡上面的数据,SD卡上面的数据当app卸载之后还会存在的。
清除缓存
缓存是程序运行时的临时存储空间,它可以存放从网络下载的临时图片,从用户的角度出发清除缓存对用户并没有太大的影响,但是清除缓存后用户再次使用该APP时,由于本地缓存已经被清理,所有的数据需要重新从网络上获取。为了在清除缓存的时候能够正常清除与应用相关的缓存,请将缓存文件存放在getCacheDir()或者 getExternalCacheDir()路径下。
以上便是Android系统中管存储目录的一些知识。
关于作者
专注于 Android 开发多年,喜欢写 blog 记录总结学习经验,blog 同步更新于本人的公众号,欢迎大家关注,一起交流学习~
作者:crazyandcoder
链接:https://juejin.im/post/5de7772af265da3398561133
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
一篇文章搞懂android存储目录结构的更多相关文章
-
一篇文章搞懂Android组件化
网上组件化的文章很多,我本人学习组建化的过程也借鉴了网上先辈们的文章.但大多数文章都从底层的细枝末节开始讲述,由下而上给人一种这门技术“博大精深”望而生畏的感觉.而我写这篇文章的初衷就是由上而下,希望 ...
-
一篇文章搞懂高级程序员、架构师、技术总监、CTO从薪资到技能的区别
一篇文章搞懂高级程序员.架构师.技术总监.CTO从薪资到技能的区别 http://youzhixueyuan.com/senior-programmers-architects-technical-d ...
-
一篇文章搞懂python2、3编码
说在前边: 编码问题一直困扰着每一个程序员的编程之路,如果不将它彻底搞清楚,那么你的的这条路一定会走的格外艰辛,尤其是针对使用python的程序员来说,这一问题更加显著, 因为python有两个版本, ...
-
五分钟学Java:一篇文章搞懂spring和springMVC
原创声明 本文作者:黄小斜 转载请务必在文章开头注明出处和作者. 本文思维导图 什么是Spring,为什么你要学习spring? 你第一次接触spring框架是在什么时候?相信很多人和我一样,第一次了 ...
-
一篇文章搞懂filebeat(ELK)
本文使用的filebeat是7.7.0的版本本文从如下几个方面说明: filebeat是什么,可以用来干嘛 filebeat的原理是怎样的,怎么构成的 filebeat应该怎么玩 一.filebeat ...
-
一篇文章搞懂G1收集器
一.何为G1收集器 The Garbage-First (G1) garbage collector is a server-style garbage collector, targeted for ...
-
Java多线程详解——一篇文章搞懂Java多线程
目录 1. 基本概念 2. 线程的创建和启动 2.1. 多线程实现的原理 2.2.多线程的创建,方式一:继承于Thread类 2.3.多线程的创建,方式一:创建Thread匿名子类(也属于方法一) 2 ...
-
一篇文章搞懂DOM
学习JavaScript肯定是会遇到DOM操作,那么什么是DOM?它又是干嘛用的?这篇文章为你揭晓答案. DOM是document object model的缩写,简称文档对象模型. 简单的说DOM是 ...
-
InfluxDB从原理到实战 - 一篇文章搞懂InfluxDB时区
0x00 简介 InfluxDB默认以UTC时间存储并返回时间戳,当接收到一个时序数据记录时,InfluxDB将时间戳从本地时区时间转换为UTC时间并存储,查询时,InfluxDB返回的时间戳对 ...
随机推荐
-
iOS调节系统音量
目录[-] 使用MPVolumeView 编程实现系统音量调节2 通过MPVolumeSlider的实例来操作系统音量 有问题!我不喜欢系统弹出音量提示 还有问题,我修改了系统音量但是不是通过我的UI ...
-
Ditto在教学上的应用
Ditto在教学上的应用 我喜欢iOS和macOS生态的一个原因是,你在iphone上看到一段好文字,复制一下,到macbook中粘贴一下就可以了,这体验太爽了. 大家可能相信大家都听过这样一则笑话: ...
-
.NET Core 开源工具 IPTools - 快速查询 IP 地理位置、经纬度信息
快速查询IP信息,支持国内和国外IP信息查询,支持查询经纬度,地理位置最高支持到城市. 1. IPTools.China 快速查询中国IP地址信息,包含国家.省份.城市.和网络运营商.非中国IP只支持 ...
-
vue脚手架中使用axios
虽然之前用过n次,但大多都是直接在页面中引入axios.js的.今天想换种方式使用,一时间竟不知道怎么配置了.特此记录下. 1.npm 安装axios,文件根目录下安装,指令如下: npm inst ...
-
【转载】Win10桌面图标有小箭头怎么去掉?Win10去掉桌面图标小箭头的方法
以下文章转载至系统之家 网址:http://www.xitongzhijia.net/xtjc/20190104/146560.html Win10桌面图标有小箭头怎么去掉?Win10去掉桌面图标小箭 ...
-
LeetCode题解-147 对链表进行插入排序
对链表进行插入排序. 插入排序的动画演示如上.从第一个元素开始,该链表可以被认为已经部分排序(用黑色表示). 每次迭代时,从输入数据中移除一个元素(用红色表示),并原地将其插入到已排好序的链表中. 插 ...
-
java并发编程:线程安全管理类--原子操作类--AtomicInteger
在java并发编程中,会出现++,--等操作,但是这些不是原子性操作,这在线程安全上面就会出现相应的问题.因此java提供了相应类的原子性操作类. 1.AtomicInteger
-
【VS2015】故障修复之dep6100,dep6200
问题描述:把uwp程序往手机上(或者往模拟器上)部署时,vs ide提示我错误信息dep6100和dep6200,报告说“连接不到设备”. 这可把我愁坏了,各种方法都不行,最后发现问题出在Hyper- ...
-
覆写Activity的finish()方法
MainActivity如下: package cn.testfinish; import android.app.Activity; import android.os.Bundle; import ...
-
Bash 实例,第一部分
您可能要问:为什么要学习 Bash 编程?好,以下是几条令人信服的理由: 已经在运行它 如果查看一下,可能会发现:您现在正在运行 bash.因为 bash 是标准 Linux shell,并用于各种目 ...