Android: 内部存储与外部存储
在说这两个概念以前,我们需要弄懂三个名词的区别:内存、内部存储、外部存储。
内存(RAM): Random Access Memory, 也叫主存。是与CPU直接交换数据的内部存储器。它可以随时读写(刷新时除外),而且速度很快,通常作为操作系统或其他正在运行中的程序的临时数据存储介质 。摘自 维基百科
内部存储(ROM): Internal Storage, 注意内部存储不是内存,如果将文件存在内部存储中,那么只能被自己的程序访问到。且一个程序所创建的文件都在和应用包名相同的目录下。 参考自 泡在网上的日子
外部存储(ROM): External Storage, 概念上有点复杂,可以酱紫区别:将手机连上电脑,能被电脑识别,就是外部存储。参考自 泡在网上的日子
接下来我们看一下安卓内部文件结构,这是机顶盒的文档结构,直接进串口看的。安卓机的话,可以看看 参考链接 中查看文档列表的方法。
标红的三个部分为我们需要关注的文件夹。接下来就进入正题。
一. 内部存储
data 目录为 内部存储 的文件夹,里面一般有两个文件夹需要我们注意:
如图所示,我们需要关注 app 和 data 两个文件夹。
app: app 文件夹中存储的是 .apk 文件,是所有我们安装的应用(不包括系统应用)。
data: data 中存储的是所有程序的包名,每个包中都会有如下几个文件夹:
- data/data/包名/files: 存储普通文件
- data/data/包名/databases: 存储数据库文件
- data/data/包名/shared_prefs: 存储本地化持久数据
- data/data/包名/cache: 存储缓存
- data/data/包名/code_cache: 存储由运行时应用程序生成的编译或优化的代码
内部存储的特点:始终可用,不可共享
二. 外部存储
外部存储一般分为 扩展卡内存 和 SD卡 , 一般来说,mnt (或 storage ) 为外部存储的文件夹,外部存储下一般会有 sdcard 文件夹,这个是 SD卡 的路径。而扩展卡内存,一般为 /mnt/sda/sda1 这类格式。
SD卡(mnt/sdcard 或 storage/sdcard)
九大公有目录,目录中的所有文件均可以被其它程序读取
- DCIM(Digital Camera Images),存储 相机 图片、视频文件
- Pictures:存储用户非相机拍摄的可用图片文件
- Download:存储用户下载文件的标准目录
- Movies:存储可用电影文件
- Alarms:存储闹钟音频文件
- Notifications:存储通知列表中的音频文件
- Ringtones:存储铃声列表中的音频文件
- Podcasts:存储播客列表中的音频文件
- Music:存储其它音频文件(音乐等…)
私有目录
Android/data 即为私有目录。data 下放着一系列包名组成的文件,与内部存储的 data/data 有点像。每个包名代表对应应用程序的私有目录。把文件放在这里,会减轻内部存储的压力,但是会将数据暴露给用户和其它程序。
扩展卡内存
扩展卡内存 即用户插入的外置 SD卡,没有直接的方法可以获取到扩展卡的路径。获取扩展卡内存的路径可以参考 这里
外部存储的特点: 并非一直可用、全局可读
三. 总结内 / 外存储目录
- 内部存储目录: /data
- 外部存储目录:
- 内置 SD 卡:/mnt/sdcard 或者 /storage/sdcard
- 扩展 SD 卡: /mnt/sda/ /mnt/sdb 或 /storage/sda /storage/sdb
四. 操作存储空间
Google 官方建议 app 的数据应该存储在外部存储的私有目录 /mnt/sdcard/Android/data/ 或 /storage/sdcard/Android/data 下。这样当用户卸载 app 时,会将相关的数据一并删除。
我们可以将文件目录按 是否拥有包名 来进行分类:
拥有包名的路径
<tr> <td rowspan="5" align="center"><b>内部存储<br> /data/data/包名/</b></td> <td>files</td> <td>context.getFilesDir()</td> </tr> <tr> <td>cache</td> <td>context.getCacheDir()</td> </tr> <tr> <td>shared_prefs</td> </tr> <tr> <td>code_cache</td> <td>context.getCodeCacheDir() (API level 21)</td> </tr> <tr> <td>databases</td> <td>context.getDataDir() (API level 24)</td> </tr> <tr> <td rowspan="2" align="center"><b>外部存储(mnt 或 storage)<br> /mnt/sdcard/ 或 /storage/sdcard/</b></td> <td>Android/data/包名/files</td> <td>context.getExternalFiles("文件夹名")</td> </tr> <tr> <td>Android/data/包名/cache</td> <td>context.getExternalCacheDir()</td> </tr>
可以看到,所有拥有包名路径的基本都可以使用 context
来获取到对应文件
下面我们用代码来看一下
1 | File internalFiles = mContext.getFilesDir(); |
打印结果
不拥有包名的路径
可以使用
Environment
来获取到对应路径。Environment
有以下方法获取到指定目录:1
2
3
4
5
6
7public static File getDataDirectory();
public static File getExternalStorageDirectory();
public static File getDownloadCacheDirectory();
public static File getRootDirectory();
// 获取九大公有目录
// 例:File music = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC);
public static File Environment.getExternalStoragePublicDirectory(String type);下面我们来看一下使用上述方法后的打印结果(具体代码就不贴了)
五. 参考文档
六. 最后
整篇文章基于 Android API 19。对于 Android 6.0 后的多用户特性,内部存储通过同样的方法,会拿到类似于 /data/user/0/包名/xxx 之类的路径,这个在以后的文章中再做说明(主要是现在还没有了解到啦~)。