Android 开发中基本都要使用到文件的保存和读取操作,我们一般遇见的文件读写问题有几个:文件保存在哪?以及如何使用相关函数,目录权限的问题?以及删除应用之后目录是否会随之删除的问题?接下来就来解析一下这几个相关目录的操作函数。
[android 最全缓存目录获取方式和函数解析][1]
我们这里假设应用的名字叫做 com.android.framework:
/data/data/package_name/ 目录
对应的目录名字为 /data/data/com.android.framework/。
该目录是只对应用可见的,而且如果手机没有 root,用普通权限的 adb 也看不了这个目录,该目录用来存储和应用周期相关的文件,会随着应用的卸载一起删除,相关的子目录如下所示:
/data/data/com.android.framework/shared_prefs/
用来存储 SharedPreference,对应函数为:getSharedPreferences(String fileName, int mode);
/data/data/com.android.framework/databases/
用来存储数据库 DB,相关函数还有 getDatabasePath();
/data/data/com.android.framework/app_webview 和 /data/data/com.android.framework/xxxwebviewcachexxx
来存储应用内置 webview 所产生的 cache 和 cookies 等,该目录由于 android 版本不同名字和位置也可能不同;
/data/data/com.android.framework/lib
用来存储该应用的 .so 静态库文件;
/data/data/com.android.framework/cache
该目录可以使用函数 getCacheDir() 获取;
/data/data/com.android.framework/files
该目录可以使用函数 getFilesDir() 获取,openFileInput() 和 openFileOutput() 函数也是在该目录下操作文件, fileList() 函数是用来列出该 files 目录下的所有文件,deleteFile(String name) 用来删除该 files 目录下的文件;
/data/data/com.android.framework/XXXX
这个目录下面当然也能够创建子集的目录,使用的方法就是 getDir(String name, int mode),参数中的 name 就是需要在该目录下创建的子目录名字。
如果能够打开应用的该目录,一般会在该目录下看到很多子目录。
PS:还有一个特别奇怪的函数,无意中看见的 getCodeCacheDir() 函数,该函数的解释为 This location is optimal for storing compiled or optimized code generated by your application at runtime,该目录适合在运行时存放应用产生的编译或者优化的代码,但是我调用就报了 NoSuchMethodError,不知道为什么,知道的可以告诉我。
另外还有其他两个相关函数:
getPackageCodePath() = /data/app/com.android.framework-1.apk;
getPackageResourcePath() = /data/app/com.android.framework-1.apk。
注:以上函数没有明确指定的都是使用 Context 调用。
SD 卡下的目录
SD 卡下的目录,顾名思义就是需要插入 SD 卡,当 SD 卡不可用时这两个目录都是无效的,SD 卡下面也分为应用的私有目录和共有目录,私有目录的生命周期也是和应用挂钩的,卸载之后就会被删除,共有目录不会随着应用的卸载而删除。
可以通过 Environment.getExternalStorageState() 函数来获取 SD 卡的挂载状态,当该函数返回 mounted 的时候,代表 SD 卡可用。
注意 SD 卡使用时需要注册相关权限:
SD 卡私有目录
该目录下的文件卸载应用之后会自动删除。
/sdcard/Android/data/package_name/
对应为 /sdcard/Android/data/com.android.framework/。
Android/data/com.android.framework/files/
该目录可用 getExternalFilesDir(String type) 和 getExternalFilesDirs(String type) 获取,参数 type 为子目录名字,null 则为根目录,后者调用之后会自动生成该目录,并且后者返回的是一个数组,如果插入外置存储卡,外置存储卡目录也会一并返回,具体区别可以查看后面的源码和结果;
Android/data/com.android.framework/cache/
该目录可用 getExternalCacheDir() 和 getExternalCacheDirs() 获取,后者调用之后自动生成该目录,和上面一样,后者返回的是一个数组,如果插入外置存储卡,外置存储卡目录也会一并返回,具体区别可以查看后面的源码和结果。
/sdcard/Android/obb/package_name/
对应为 /sdcard/Android/obb/com.android.framework/。
需要注意的是,obb 目录也可能不存在,原文:Note if the application does not have any OBB files, this directory may not exist,一般游戏 APP 会将游戏相关的数据包放到这个目录下。
该目录的的相关函数简单只有两个:getObbDirs() 和 getObbDir(),前者调用之后会自动生成该目录,后者在插入外置存储卡之后会在前者的基础上另外返回外置存储卡的 obb 目录,具体的结果可以查看后面的源码和结果。
SD 卡共有目录
该目录下的文件卸载应用之后还会留存,所以为了 SD 卡的整洁度,不要随便在 SD 卡的根目录下面创建文件,最好以应用名字创建一个目录,所有的需要卸载之后留存或者需要给其他应用共享的文件都放到该目录下,不要在根目录下创建文件,还有一个公司的多个应用最好共享一个目录,特别讨厌 360 ,恨不得把 360XXX 式的目录全部创建完才行,极其讨厌和反对。
/sdcard/(any_folder_name)
对应为 /sdcard/XXX。
Environment.getExternalStorageState()
这个函数用来获取 SD 卡的挂载状态,如果传入参数 path 则是获取该路径的的挂载状态,比如这个目录被用户的 PC 挂载,或者从设备中移除,或者其他问题发生,状态的返回是不一样的;
Environment.getExternalStorageDirectory()
该函数用来返回 SD 卡的根目录,即 /storage/emulated/0,注意不要在根目录下创建文件,强烈建立创建一个子目录去操作,要不然会污染 SD 卡的主目录,该目录所有应用都可操作,为共享目录;
Environment.getDownloadCacheDirectory()
该函数用来返回 SD 卡下面的下载缓存目录;
Environment.getDataDirectory()
该函数用来获取用户的数据目录;
Environment.getExternalStoragePublicDirectory(String type)
该函数用来根据类型返回相关目录,类型为 Environment 的一些变量,传入的类型参数不能是 null,返回的目录路径有可能不存在,所以必须在使用之前确认一下,没有就创建该目录;
Environment.getRootDirectory()
该函数用来返回根 System 目录,只挂载为只读;