在近期的app安全检测中,说的app存在胡乱操作存储卡的行为,建议将被测系统自身数据存放在系统的安装目录下。那么什么是系统的安装目录,应该怎么做?我们今天一步步来深入了解一下。
Andorid系统有五种数据持久化的方式:
android持久化方式
Android手机的存储分为:内部存储和外部储存,在Android4.4以前,手机机身存储就叫内部存储,插入的SD卡就是外部存储,但是在Android4.4以后这两个存储的定义又有了一些些变化,新的手机不再有外插SD卡的概念,采取了内置闪存(eMMC、UFS等)的方式,所以内部存储和外部存储在新的Android手机上已经在同一个硬件上了。手机机身自带的存储也是外部存储,如果再插入SD卡的话也叫外部存储,不过现在也几乎没有在采用扩展卡内存这种方式来增加手机存储空间了,手机自带的外部存储足矣,除此以外还有一种公有目录存储,它返回的目录全都是共享的公有目录。同时也是造成Android手机文件存储混乱的罪魁祸首! 。
1.内部存储(Internal Storage)
内部存储位于系统中很特殊的一个位置,对于设备中每一个安装的 App,系统都会在 data/data/packagename/xxx 自动创建与之对应的文件夹。如果你想将文件存储于内部存储中,那么文件默认只能被你的应用访问到,且一个应用所创建的所有文件都在和应用包名相同的目录下。也就是说应用创建于内部存储的文件,与这个应用是关联起来的。当一个应用卸载之后,内部存储中的这些文件也被删除。对于这个内部目录,用户是无法访问的,除非获取root权限。
内部存储空间的获取都需要使用Context,当然Activity中也可以省略
1.1 context.getFileDir()
String fileDir = this.getFilesDir().getAbsolutePath();
打印:
image.png
通常对应 内部存储的路径为 data/data/packagename/files,但我的测试手机是小米,而华为和小米手机获取到的路径为:data/user/0/packagename/files。注意:/data/user/0/ 等同于 /data/data/
说明:
可用于用于存放私有持久文件。
非常适合用于存放app各种伴随app运行周期所需要的文件数据,它既不会因为手机存储空间不足而被清理,也不会因卸载app而遗留数据垃圾,并且它是私有的。
1.2 context.getCacheDir()
String cacheDir = this.getCacheDir().getAbsolutePath();
image.png
通常对应内部存储的路径为:data/data/packagename/cache,但我的测试手机是小米,而华为和小米手机获取到的路径为:data/user/0/packagename/cache。该目录内的文件在设备内存不足时会优先被删除掉,所以存放在这里的文件是没有任何保障的,可能会随时丢掉。
说明:
专门用于存放缓存数据。
用户对app进行缓存清理的时候会清理缓存目录cache的数据,手机空间不足的时候系统也会对缓存目录内的数据进行清理。开发者仍要管理好缓存数据特别是内部存储的缓存,避免缓存数据过大。
1.3 context.getDir(String name,int mode)
代码:
String dir =this.getDir("spanner",MODE_PRIVATE).getAbsolutePath();
Log.e(TAG, "onCreate: "+dir);
打印:
image.png
说明:
归类存放私有文件。
在内部私有目录下会创建一个名为app_name的文件夹,mode以前是可以设置文件夹私有(MODE_PRIVATE)和公有的(MODE_WORLD_READABLE、MODE_WORLD_WRITEABLE),但目前公有的mode都已经废弃,意味着这个api创建的文件夹已经完全私有,不能再共享出去了。
2.外部存储(External Storage/ Shared Storage)
外部存储也需要通过context来获取,同时在app卸载之后,这些文件也会被删除。类似于内部存储.
外部存储并不总是可用的,因为外部存储可以移除(早期设备)或者作为USB存储设备连接到PC,访问前必须检查是否挂载(mounted):
我这里展示判断外部存储是否存在的操作代码:
private void getExternalStotageState(){
//获取状态
String externalStorageState =Environment.getExternalStorageState();
//判断是否存在
if(externalStorageState.equals(Environment.MEDIA_MOUNTED)){
Log.e("externalStorageState", "sd卡已经安装,可以进行相关文件操作");
}else{
Log.e("externalStorageState", "sd卡状态:"+externalStorageState);
}
}
2.1 Context.getExternalCacheDir()
代码:
String externalCacheDir =this.getExternalCacheDir().getAbsolutePath();
Log.e("externalCacheDir", externalCacheDir);
结果:
image.png
说明:
专门用于存放缓存数据,和内部存储的getCacheDir()相似。
2.2 Context.getExternalFilesDir(String type)
public static String DIRECTORY_MUSIC = "Music";
String externalFileDir =this.getExternalFilesDir(DIRECTORY_MUSIC).getAbsolutePath();
Log.e("externalFileDir", externalFileDir);
打印:
image.png
getExternalFilesDir(String type),type类型你可以根据自己存储文件的类型来定义,会响应的创建出该文件夹。
说明:
归类存放公有文件
如果type不为null的话在外部私有目录下创建返回一个名为type的文件夹,为null直接返回外部私有根目录。如无特别需要,个人的做法是传入Environment的DIRECTORY常量进行文件夹创建。
2.3getExternalMediaDirs()
代码:
//获取外存媒体文件
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
File[] files =this.getExternalMediaDirs();
for (File file : files) {
Log.e("file_dir", file.getAbsolutePath());
}
}
打印:
image.png
说明:
可存放共享媒体文件
这个是在Android 5.0加入的api,创建和获取位于/sdcard/Android/media目录下的应用目录,该目录下的文件能够被其他应用访问和被MediaStore查询和获取
3. 公有目录
公有目录里面的文件是可以被自由访问,即文件的数据对其他应用或者用户来说都是可以访问的,当应用被卸载之后,其卸载前创建的文件仍然保留。
对于公有目录上面的文件路径需要通过Environment获取
3.1 getExternalStorageDirectory()
//SD卡外部存储路径
String externalStoragePath =Environment.getExternalStorageDirectory().getPath();
Log.e("externalStoragePath", externalStoragePath);
打印:
image.png
3.2 getExternalStoragePublicDirectory(String type)
String eSPublicMusic = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC).getPath();
Log.e("externalStoragePath共享音乐", eSPublicMusic);
结果:
image.png
说明:
使用频率极高的api,返回在根目录下的名为type的文件夹,我把它分为两种用法:一种是传入Environment的DIRECTORY常量再创建子目录使用;一种是传入appPackageName或者易被识别归属的名称创建子目录使用。前者会比较通用,内容可以被各种工具app搜索发现(包括微信);后者算是私用,可以存放不跟随app生命的文件,即卸载后也可以保留。
Environment.DIRECTORY_DCIM是手机的相册。
Environment.DIRECTORY_PICTURES用于存放各种“正式的”图片,强烈建议在这里创建文件夹存放你想要被用户发现的图片,并且微信会扫描这个文件夹,让你的图片更容易分享。
Environment.DIRECTORY_DOWNLOADS可以用于存放app更新的apk等下载资源
4.系统存储目录
4.1getRootDirectory()
对应获取系统分区根路径:/system
4.2 getDataDirectory()
对应获取用户数据目录路径:/data
4.3 getDownloadCacheDirectory()
对应获取用户缓存目录路径:/cache,
5.清除数据和清除缓存的区别
5.1清除数据
清除数据清除的是保存在app中所有数据,就是上面提到的位于packagename下面的所有文件,包含内部存储(/data/data/packagename/)和外部存储(/storage/emulated/0/Android/data/packagename/)。当然除了SD卡上面的数据,SD卡上面的数据当app卸载之后还会存在的。
5.2清除缓存
缓存是程序运行时的临时存储空间,它可以存放从网络下载的临时图片,从用户的角度出发清除缓存对用户并没有太大的影响,但是清除缓存后用户再次使用该APP时,由于本地缓存已经被清理,所有的数据需要重新从网络上获取。为了在清除缓存的时候能够正常清除与应用相关的缓存,请将缓存文件存放在getCacheDir()或者 getExternalCacheDir()路径下。