Android 文件系统

在 Android Studio 可以在 DDMS 的 File Exploer 窗口中查看文件系统,下图就是一个 Android 文件系统目录。

Android 存储分类 (/data 目录和 /sdcard 目录)

Android 的存储可以分为三类:内存、内置 SD 卡,外置 SD 卡

一、内部存储

对应的就是 /data 目录,需要系统 root 之后才能查看,该目录下有很多子目录,其中对于软件开发比较重要的是:

1、 /data/app

该文件夹存放着系统中安装的第三方应用的 apk 文件,当我们调试一个app的时候,可以看到控制台输出的内容,有一项是
uploading ……就是上传我们的apk到这个文件夹,上传成功之后才开始安装。

Android 中应用的安装就是将应用的安装包原封不动地拷贝到 /data/app 目录下,每个应用安装包本质上就是一个 zip 格式的压缩文件。为了提升应用的启动效率,Android 会将解压出来的 dex 格式的应用代码文件解析提取后,缓存在 /data/dalvik-cache 目录下。

2、/data/data

该文件夹存放存储包私有数据,对于设备中每一个安装的 App,系统都会在内部存储空间的 data/data 目录下以应用包名为名字自动创建与之对应的文件夹。
用户卸载 App 时,系统自动删除 data/data 目录下对应包名的文件夹及其内容。
该目录下又把存储内容进行了分类:

data/data/包名/cache: 存放的 APP 的缓存信息
data/data/包名/databases: 存放 APP 的数据库信息
data/data/包名/files: 存放 APP 的文件信息
data/data/包名/shared_prefs: 存放 APP 内的 SharedPreferences

3、API

1 /data

Environment.getDataDirectory();

2 /data/data/包名/files

context.getFilesDir();

对于 Files 目录下的文件,通常不会通过 File 类的方式直接进行读写,而是利用一些封装过的类或函数进行操作:

public FileInputStream openFileInput(String name)
public FileOutputStream openFileOutput(String name, int mode)

还可以直接删除或查询该目录下的文件:

context.deleteFile(name)
context.fileList()

3 /data/data/包名/cache

context.getCacheDir();

4 /data/data/包名/shared_prefs

context.getSharedPreferences(name,mode)//返回的是 SharedPreferences 对象
context.deleteSharedPreferences(name)

5 /data/data/包名/databases

context.getDataDir()
context.getDatabasePath(name)
context.deleteDatabase(name)

6 /data/data/包名/app_name

context.getDir(name,mode)

经测试该方法会在 /data/data/包名/ 目录下生成一个以 app_ 开头的目录

二、外部存储

每个兼容 Android 的设备都支持可用于保存文件的共享“外部存储”。 该存储可能是可移除的存储介质(例如 SD 卡)或内部(不可移除)存储。 保存到外部存储的文件是全局可读取文件,而且,在计算机上启用 USB 大容量存储以传输文件后,可由用户修改这些文件。


外部存储在 Android 文件系统中是 sdcard 目录,这里只是一个快捷方式,真正的目录是 /storage/emulated/legacy 文件夹

1、获取外存路径和状态

要读取或写入外部存储上的文件,应用必须获取READ_EXTERNAL_STORAGE 或 WRITE_EXTERNAL_STORAGE系统权限。

1 获取状态
Environment.getExternalStorageState()

返回值是以下一种:

MEDIA_UNKNOWN
MEDIA_REMOVED
MEDIA_UNMOUNTED
MEDIA_CHECKING
MEDIA_NOFS
MEDIA_MOUNTED
MEDIA_MOUNTED_READ_ONLY
MEDIA_SHARED
MEDIA_BAD_REMOVAL
MEDIA_UNMOUNTABLE

2 获取目录
Environment.getExternalStorageDirectory()

返回的路径是 /storage/emulated/0

2、公共目录

Android 在外部存储上提供了十个公共目录来存储相对应的文件:
通过 API Environment.getExternalStoragePublicDirectory(type) 来访问

  • DIRECTORY_MUSIC:/storage/emulated/0/Music
  • DIRECTORY_PODCASTS:/storage/emulated/0/Podcasts
  • DIRECTORY_RINGTONES:/storage/emulated/0/Ringtones
  • DIRECTORY_ALARMS:/storage/emulated/0/Alarms
  • DIRECTORY_NOTIFICATIONS:/storage/emulated/0/Notifications
  • DIRECTORY_PICTURES:/storage/emulated/0/Pictures
  • DIRECTORY_MOVIES:/storage/emulated/0/Movies
  • DIRECTORY_DOWNLOADS:/storage/emulated/0/Downloads
  • DIRECTORY_DCIM:/storage/emulated/0/Dcim
  • DIRECTORY_DOCUMENTS:/storage/emulated/0/Documents

三、私有目录

Android2.2 引入了基于扩展存储器的应用缓存目录,该目录指向大容量的扩展存储器。与应用的内存私有目录一样,缓存目录会随着应用的卸载一并删除。
和内部存储一样,会在 SD 卡的 Android/data 目录下生成对应包名的文件夹

1 /storage/emulated/0/Android/data/应用包名/files
context.getExternalFilesDir(type)

2 /storage/emulated/0/Android/data/应用包名/cache

context.getExternalCacheDir()

3 在 Android 目录下除了 data 目录还有一个 obb 目录
/storage/emulated/0/Android/obb/应用包名

context.getObbDir()

Android 文件系统一些其它目录(可以忽略这部分,用的并不多)

1 /cache 目录

通过 API Environment.getDownloadCacheDirectory() 访问,存储下载文件的缓存路径
比如app有一些下载到本地的文件,又不想app卸载后被删除,可以放在这个地方.利用公共目录或者这里的缓存目录,而不需要启动app后,开发者自己创建文件路径

2 /system 目录

通过 API Environment.getRootDirectory() 访问,该目录下也有一个 app 目录,存放的是系统应用的 apk 文件。

/system/app 和 /data/app 的区别
/data/app 里软件权限没全开,/system/app 里的软件获取了所有权限
/data/app 可以应用卸载,/system/app 只能 root 后删除
/data/app 文件夹大小随便,/system/app 文件夹有大小限制
卸载/system/app 目录下的文件并不会增加系统空间,即可用 ROM 空间

3 /mnt 目录

这个目录专门用来当作挂载点挂在外部设备的,如 SD 卡,sdcard
将会被系统视作一个文件夹,这个文件夹将会被系统嵌入到收集系统的 mnt 目录中,所以在 /mnt 目录下也会看到一个 sdcard 的快捷方式:

附:

Android获取各种系统路径的方法

Android 文件系统一些其它目录
  • Environment.getDataDirectory() /data
  • Environment.getDownloadCacheDirectory() /cache
  • Environment.getRootDirectory() /system
公有目录
Environment.getExternalStoragePublicDirectory(DIRECTORY_ALARMS)  /storage/sdcard0/Alarms
Environment.getExternalStoragePublicDirectory(DIRECTORY_DCIM)   /storage/sdcard0/DCIM
Environment.getExternalStoragePublicDirectory(DIRECTORY_DOWNLOADS)  /storage/sdcard0/Download
Environment.getExternalStoragePublicDirectory(DIRECTORY_MOVIES) /storage/sdcard0/Movies
Environment.getExternalStoragePublicDirectory(DIRECTORY_MUSIC)  /storage/sdcard0/Music
Environment.getExternalStoragePublicDirectory(DIRECTORY_NOTIFICATIONS)  /storage/sdcard0/Notifications
Environment.getExternalStoragePublicDirectory(DIRECTORY_PICTURES)   /storage/sdcard0/Pictures
Environment.getExternalStoragePublicDirectory(DIRECTORY_PODCASTS)   /storage/sdcard0/Podcasts
Environment.getExternalStoragePublicDirectory(DIRECTORY_RINGTONES)  /storage/sdcard0/Ringtones
私有目录
  • getExternalFilesDir() /storage/emulated/0/Android/data/cwj.test(包名)/files/test
  • getExternalCacheDir /storage/emulated/0/Android/data/cwj.test(包名)/cache/test
通过Context获取的
  • Context.getDatabasePath() 返回通过Context.openOrCreateDatabase 创建的数据库文件
  • Context.getCacheDir().getPath() : 用于获取APP的cache目录/data/data//cache目录
  • Context.getExternalCacheDir().getPath() : 用于获取APP的在SD卡中的cache目录/mnt/sdcard/android/data//cache
  • Context.getFilesDir().getPath() : 用于获取APP的files目录 /data/data//files
  • Context.getObbDir().getPath(): 用于获取APPSDK中的obb目录/mnt/sdcard/Android/obb/
  • Context.getPackageName() : 用于获取APP的所在包目录
  • Context.getPackageCodePath() : 来获得当前应用程序对应的 apk 文件的路径
  • Context.getPackageResourcePath() : 获取该程序的安装包路径
完整 操作手机文件 工具类
public void saveToPhone(View v) {
//        FileDir();SDCardTest();}private void FileDir() {boolean mExternalStorageAvailable = false;boolean mExternalStorageWriteable = false;String state = Environment.getExternalStorageState();if (Environment.MEDIA_MOUNTED.equals(state)) {// We can read and write the mediamExternalStorageAvailable = mExternalStorageWriteable = true;} else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {// We can only read the mediamExternalStorageAvailable = true;mExternalStorageWriteable = false;} else {// Something else is wrong. It may be one of many other states, but all we need//  to know is we can neither read nor writemExternalStorageAvailable = mExternalStorageWriteable = false;}Log.i("codecraeer", "getFilesDir = " + getFilesDir());Log.i("codecraeer", "getExternalFilesDir = " + getExternalFilesDir("exter_test").getAbsolutePath());Log.i("codecraeer", "getDownloadCacheDirectory = " + Environment.getDownloadCacheDirectory().getAbsolutePath());Log.i("codecraeer", "getDataDirectory = " + Environment.getDataDirectory().getAbsolutePath());Log.i("codecraeer", "getExternalStorageDirectory = " + Environment.getExternalStorageDirectory().getAbsolutePath());Log.i("codecraeer", "getExternalStoragePublicDirectory = " + Environment.getExternalStoragePublicDirectory("pub_test"));}/*** SDcard操作*/public void SDCardTest(){try {//获取扩展SD卡设备状态String sDStateString = Environment.getExternalStorageState();//拥有可读可写权限if(sDStateString.equals(Environment.MEDIA_MOUNTED)){//获取扩展存储设备的文件目录File SDFile = Environment.getExternalStorageDirectory();String fileDirectoryPath=SDFile.getAbsolutePath()+File.separator+"测试文件夹";File fileDirectory=new File(fileDirectoryPath);//打开文件File myFile = new File(fileDirectoryPath+File.separator+"MyFile.txt");//判断是否存在,不存在则创建if (!fileDirectory.exists()) {//按照指定的路径创建文件夹fileDirectory.mkdirs();}if (!myFile.exists()) {try {//在指定的文件夹中创建文件myFile.createNewFile();} catch (Exception e) {}}//写数据String szOutText="Hello, World!+姚佳伟";FileOutputStream outputStream=new FileOutputStream(myFile);outputStream.write(szOutText.getBytes());outputStream.close();}//拥有只读权限else if(sDStateString.endsWith(Environment.MEDIA_MOUNTED_READ_ONLY)){//获取扩展存储设备的文件目录File SDFile=android.os.Environment.getExternalStorageDirectory();//创建一个文件File myFile=new File(SDFile.getAbsolutePath()+File.separator+"MyFile.txt");//判断文件是否存在if(myFile.exists()){//读数据FileInputStream inputStream=new FileInputStream(myFile);byte[]buffer=new byte[1024];inputStream.read(buffer);inputStream.close();}}} catch (IOException e) {e.printStackTrace();Log.d("yjw","检查权限");}}

public class FileUtils {static String directoryPath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "FileDemo" + File.separator;String fileName = directoryPath + getISO8601TimeFileName() + ".txt";//创建文件夹及文件public void CreateText() throws IOException {File file = new File(directoryPath);if (!file.exists()) {try {//按照指定的路径创建文件夹file.mkdirs();} catch (Exception e) {// TODO: handle exception}}File dir = new File(fileName);if (!dir.exists()) {try {//在指定的文件夹中创建文件dir.createNewFile();} catch (Exception e) {}}}//向已创建的文件中写入数据public void print(String str) {FileWriter fw = null;BufferedWriter bw = null;String datetime = "";try {CreateText();SimpleDateFormat tempDate = new SimpleDateFormat("yyyy-MM-dd" + " " + "hh:mm:ss");datetime = tempDate.format(new java.util.Date()).toString();fw = new FileWriter(fileName, true);//// 创建FileWriter对象,用来写入字符流/*** 如果想要每次写入,清除之前的内容,使用FileOutputStream流*/bw = new BufferedWriter(fw); // 将缓冲对文件的输出String myreadline = datetime + "[]" + str;bw.write(myreadline + "\n"); // 写入文件bw.newLine();bw.flush(); // 刷新该流的缓冲bw.close();fw.close();} catch (IOException e) {e.printStackTrace();try {bw.close();fw.close();} catch (IOException e1) {}}}/*** 此方法为android程序写入sd文件文件,用到了android-annotation的支持库@** @param buffer   写入文件的内容* @param folder   保存文件的文件夹名称,如log;可为null,默认保存在sd卡根目录* @param fileName 文件名称,默认app_log.txt* @param append   是否追加写入,true为追加写入,false为重写文件* @param autoLine 针对追加模式,true为增加时换行,false为增加时不换行*/public synchronized static void writeFiledToSDCard(@NonNull final byte[] buffer, @Nullable final String folder, @Nullable final String fileName, final boolean append, final boolean autoLine) {new Thread(new Runnable() {@Overridepublic void run() {boolean sdCardExist = Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);String folderPath = "";if (sdCardExist) {//TextUtils为android自带的帮助类if (TextUtils.isEmpty(folder)) {//如果folder为空,则直接保存在sd卡的根目录
//                        folderPath = Environment.getExternalStorageDirectory() + File.separator;folderPath = directoryPath;} else {folderPath = Environment.getExternalStorageDirectory() + File.separator + folder + File.separator;}} else {return;}File fileDir = new File(folderPath);if (!fileDir.exists()) {if (!fileDir.mkdirs()) {return;}}File file;//判断文件名是否为空if (TextUtils.isEmpty(fileName)) {file = new File(folderPath + getISO8601TimeFileName() + ".txt");} else {file = new File(folderPath + fileName);}RandomAccessFile raf = null;FileOutputStream out = null;try {if (append) {//如果为追加则在原来的基础上继续写文件raf = new RandomAccessFile(file, "rw");raf.seek(file.length());raf.write(buffer);if (autoLine) {raf.write("\n".getBytes());}} else {//重写文件,覆盖掉原来的数据out = new FileOutputStream(file);out.write(buffer);out.flush();}Log.d("yjw", "writeFiledToSDCard===" + "文件存入成功");} catch (IOException e) {e.printStackTrace();} finally {try {if (raf != null) {raf.close();}if (out != null) {out.close();}} catch (IOException e) {e.printStackTrace();}}}}).start();}public static String getISO8601TimeFileName() {TimeZone tz = TimeZone.getTimeZone("Asia/Shanghai");DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");df.setTimeZone(tz);String nowAsISO = df.format(new Date());return nowAsISO;}
}

总结

app中自己定义的第三方非Android系统原生写法的数据库应该放在私有目录中,因为这样app卸载后可以随着删除,避免遗留bug.或者放在内部存储中
app 保存的图片缓存可以放在私有目录中
app 保存的用户下载的文件,可以保存在公共目录中
app 一些用户的配置信息可以保存在app内部存储shared_prefs中

反正一点app保存的数据最好不要放在功能公共目录,要放的话就放在内部存储或者私有目录(注意开发者自定义的路径,要防止用户清理缓存后,app出现数据为NULL的bug),除非用户自己下载好的文件才放入公共目录,用户卸载了apk也可以查看,例如歌曲.如果特别隐私的信息,例如用户的登录配置信息,应该放在内部存储中,因为需要手机root后才能被查看.

Android 存储路径浅析相关推荐

  1. Android存储路径你了解多少?

    在了解存储路径之前,先来看看Android QQ的文件管理界面,了解一下QQ的数据文件路径来源,到底是来源于什么地方? 手Q文件管理对应存储目录 我的文件:是指放在QQ指定目录下的文件:/tencen ...

  2. Android技能树 — Android存储路径及IO操作小结

    前言 最近过年刚上来,打算把自己的Android知识都整理一下. Android技能书系列: Android基础知识 Android技能树 - 动画小结 Android技能树 - View小结 And ...

  3. Android存储路径解析

    本文讲的是Android存储路径,当需要存储文件或者清除缓存时可以看一下,下面是原文链接,复制一份以防意外 彻底搞懂Android文件存储-内部存储,外部存储以及各种存储路径解惑 前言: 对于任何一个 ...

  4. android storage 路径,风儿带你了解Android存储路径。

    前言: 你对手机存储到底了解多少?从安卓4.4以后在外置内存卡中有没有存储过东西.先上两张图片. 第一张图片是酷我音乐下载设置的选项: 酷我下载截图 第二张是网易云音乐下载设置的选项: 网易云下载截图 ...

  5. android 获取默认存储路径,Android获取外置SD卡存储路径的方法

    在开发应用的过程中,经常会遇到需要获取设备存储路径的问题.而从网上看到的很多方法获取到的都是内置存储位置,并非外置SD卡路径,因此我推荐使用反射的机制来获取外置存储的路径. 通常,使用Environm ...

  6. android 获得手机外插SD卡 存储路径和存储空间

    获取存储路径: /**** <p>* Description: 获取手机外插SD 存储路径* <p>* @date 2017-4-18* @author * @param* @ ...

  7. android存储视频文件夹在哪,Android 中 视频存储路径的一个方案

    版权声明:本文为博主原创文章,未经博主允许不得转载. 在进行视频的下载时,我们经常会面临存储路径的选择,选择一个好的存储路径能对Android系统中的内存起到优化的作用.主流app下载路径分析和常见的 ...

  8. Android APP存储路径和缓存清理规范

    1. Android APP统一存储数据规范 基于Android系统对存储卡访问的各种特性,在充分保证基线的产品交互体验前提下,定义Android APP各业务开发中的可选存储路径,对应存储特性,各自 ...

  9. android手机 存储路径设置在哪里找,Android 存储路径选择方法

    Android能用来存储的地方有两个,一个是手机内置的存储空间,一个是外置的SD卡,内置的存储空间一般比较小,所以应用的缓存建议存储在外置的SD卡中. 在Android系统中如何获得存储的路径呢? p ...

最新文章

  1. UWA平台新增【UI模块】和【粒子系统】检测功能!
  2. 免费阿里云服务器超爽体验(为阿里做个广告吧)
  3. python opencv给证件照换底色
  4. 可以叫板Google的一个搜索引擎 —— DuckDuckGo
  5. 一些黑科技接口钩子 钉钉,禅道,gitlab,jenkins等
  6. FPGA复位方法总结
  7. 详解串行通信协议及其FPGA实现
  8. 嵌入式Linux开发环境搭建实验
  9. U盘插入后只显示安全删除硬件问题
  10. mysql 只读_MySQL设置只读模式
  11. 谈谈AssetStore及其脱离Unity下载方法
  12. 智慧城市同城V4 v2.2.5 [独立版全插件]同城 同城小程序 同城信息
  13. WPS怎么统计相同名称的数据_教你如何将垃圾的WPS,玩得高大上!
  14. AutoX-1. 网页瀑布流 AutoX-2. 蚂蚁王国的蜂蜜
  15. matlab中怎么贮存函数,MATLAB参数保存、调用
  16. 点餐小程序【源码好优多】
  17. mdadm彻底删除software RAID
  18. ssh远程连接发送命令行
  19. FFmpeg yasm/nasm not found or too old. Use --disable-yasm for a crippledbuild
  20. java核心技术读书笔记—继承

热门文章

  1. mysql添加有效值_物理数据库设计 - 限定列的有效值
  2. Unity超基础学习笔记(三)
  3. 编辑中的word变成只读_文档设定密级,word中是这样加密,看一篇就精通了
  4. OpenShift 4 之 GitOps(2)用ArgoCD部署应用
  5. (五)使用模型单元测试进行MLOps持续交付
  6. 准备用于AI人脸识别的数据集
  7. Android Q 不叫 Q,正式命名为 Android 10
  8. 历经十年,Windows 7 生命周期将结束,微软:快换 Windows 10
  9. Angular.js示例应用程序
  10. mysql不同的类的个数_Mysql-SQL优化-统计某种类型的个数_MySQL