參考資料:
http://www.reibang.com/p/a34c644e3431
https://mp.weixin.qq.com/s/YNMKhqvVjmWsOzh24mDCsw
https://mp.weixin.qq.com/s/Sx4fejCDTTI7nlzDpcZfKg
在近期的app安全檢測(cè)中,說(shuō)的app存在胡亂操作存儲(chǔ)卡的行為,建議將被測(cè)系統(tǒng)自身數(shù)據(jù)存放在系統(tǒng)的安裝目錄下。那么什么是系統(tǒng)的安裝目錄鲜戒,應(yīng)該怎么做尽狠?我們今天一步步來(lái)深入了解一下摇锋。
Andorid系統(tǒng)有五種數(shù)據(jù)持久化的方式:
Android手機(jī)的存儲(chǔ)分為:內(nèi)部存儲(chǔ)和外部?jī)?chǔ)存瞧掺,在Android4.4以前,手機(jī)機(jī)身存儲(chǔ)就叫內(nèi)部存儲(chǔ)店枣,插入的SD卡就是外部存儲(chǔ),但是在Android4.4以后這兩個(gè)存儲(chǔ)的定義又有了一些些變化叹誉,新的手機(jī)不再有外插SD卡的概念鸯两,采取了內(nèi)置閃存(eMMC、UFS等)的方式长豁,所以內(nèi)部存儲(chǔ)和外部存儲(chǔ)在新的Android手機(jī)上已經(jīng)在同一個(gè)硬件上了钧唐。手機(jī)機(jī)身自帶的存儲(chǔ)也是外部存儲(chǔ),如果再插入SD卡的話也叫外部存儲(chǔ)匠襟,不過(guò)現(xiàn)在也幾乎沒(méi)有在采用擴(kuò)展卡內(nèi)存這種方式來(lái)增加手機(jī)存儲(chǔ)空間了钝侠,手機(jī)自帶的外部存儲(chǔ)足矣,除此以外還有一種公有目錄存儲(chǔ)宅此,它返回的目錄全都是共享的公有目錄机错。同時(shí)也是造成Android手機(jī)文件存儲(chǔ)混亂的罪魁禍?zhǔn)祝?。
1.內(nèi)部存儲(chǔ)(Internal Storage)
內(nèi)部存儲(chǔ)位于系統(tǒng)中很特殊的一個(gè)位置父腕,對(duì)于設(shè)備中每一個(gè)安裝的 App弱匪,系統(tǒng)都會(huì)在 data/data/packagename/xxx 自動(dòng)創(chuàng)建與之對(duì)應(yīng)的文件夾。如果你想將文件存儲(chǔ)于內(nèi)部存儲(chǔ)中璧亮,那么文件默認(rèn)只能被你的應(yīng)用訪問(wèn)到萧诫,且一個(gè)應(yīng)用所創(chuàng)建的所有文件都在和應(yīng)用包名相同的目錄下。也就是說(shuō)應(yīng)用創(chuàng)建于內(nèi)部存儲(chǔ)的文件枝嘶,與這個(gè)應(yīng)用是關(guān)聯(lián)起來(lái)的帘饶。當(dāng)一個(gè)應(yīng)用卸載之后,內(nèi)部存儲(chǔ)中的這些文件也被刪除群扶。對(duì)于這個(gè)內(nèi)部目錄及刻,用戶是無(wú)法訪問(wèn)的镀裤,除非獲取root權(quán)限。
內(nèi)部存儲(chǔ)空間的獲取都需要使用Context缴饭,當(dāng)然Activity中也可以省略
1.1 context.getFileDir()
String fileDir = this.getFilesDir().getAbsolutePath();
打邮钊啊:
通常對(duì)應(yīng) 內(nèi)部存儲(chǔ)的路徑為 data/data/packagename/files,但我的測(cè)試手機(jī)是小米颗搂,而華為和小米手機(jī)獲取到的路徑為:data/user/0/packagename/files担猛。注意:/data/user/0/ 等同于 /data/data/
說(shuō)明:
- 可用于用于存放私有持久文件。
- 非常適合用于存放app各種伴隨app運(yùn)行周期所需要的文件數(shù)據(jù)丢氢,它既不會(huì)因?yàn)槭謾C(jī)存儲(chǔ)空間不足而被清理傅联,也不會(huì)因卸載app而遺留數(shù)據(jù)垃圾,并且它是私有的疚察。
1.2 context.getCacheDir()
String cacheDir = this.getCacheDir().getAbsolutePath();
通常對(duì)應(yīng)內(nèi)部存儲(chǔ)的路徑為:data/data/packagename/cache蒸走,但我的測(cè)試手機(jī)是小米,而華為和小米手機(jī)獲取到的路徑為:data/user/0/packagename/cache稍浆。該目錄內(nèi)的文件在設(shè)備內(nèi)存不足時(shí)會(huì)優(yōu)先被刪除掉载碌,所以存放在這里的文件是沒(méi)有任何保障的,可能會(huì)隨時(shí)丟掉衅枫。
說(shuō)明:
- 專門用于存放緩存數(shù)據(jù)嫁艇。
- 用戶對(duì)app進(jìn)行緩存清理的時(shí)候會(huì)清理緩存目錄cache的數(shù)據(jù),手機(jī)空間不足的時(shí)候系統(tǒng)也會(huì)對(duì)緩存目錄內(nèi)的數(shù)據(jù)進(jìn)行清理弦撩。開發(fā)者仍要管理好緩存數(shù)據(jù)特別是內(nèi)部存儲(chǔ)的緩存步咪,避免緩存數(shù)據(jù)過(guò)大。
1.3 context.getDir(String name,int mode)
代碼:
String dir =this.getDir("spanner",MODE_PRIVATE).getAbsolutePath();
Log.e(TAG, "onCreate: "+dir);
打右媛ァ:
說(shuō)明:
- 歸類存放私有文件猾漫。
- 在內(nèi)部私有目錄下會(huì)創(chuàng)建一個(gè)名為app_name的文件夾,mode以前是可以設(shè)置文件夾私有(MODE_PRIVATE)和公有的(MODE_WORLD_READABLE感凤、MODE_WORLD_WRITEABLE)悯周,但目前公有的mode都已經(jīng)廢棄,意味著這個(gè)api創(chuàng)建的文件夾已經(jīng)完全私有陪竿,不能再共享出去了禽翼。
2.外部存儲(chǔ)(External Storage/ Shared Storage)
外部存儲(chǔ)也需要通過(guò)context來(lái)獲取,同時(shí)在app卸載之后族跛,這些文件也會(huì)被刪除闰挡。類似于內(nèi)部存儲(chǔ).
外部存儲(chǔ)并不總是可用的,因?yàn)橥獠看鎯?chǔ)可以移除(早期設(shè)備)或者作為USB存儲(chǔ)設(shè)備連接到PC礁哄,訪問(wèn)前必須檢查是否掛載(mounted):
我這里展示判斷外部存儲(chǔ)是否存在的操作代碼:
private void getExternalStotageState(){
//獲取狀態(tài)
String externalStorageState =Environment.getExternalStorageState();
//判斷是否存在
if(externalStorageState.equals(Environment.MEDIA_MOUNTED)){
Log.e("externalStorageState", "sd卡已經(jīng)安裝长酗,可以進(jìn)行相關(guān)文件操作");
}else{
Log.e("externalStorageState", "sd卡狀態(tài):"+externalStorageState);
}
}
2.1 Context.getExternalCacheDir()
代碼:
String externalCacheDir =this.getExternalCacheDir().getAbsolutePath();
Log.e("externalCacheDir", externalCacheDir);
結(jié)果:
說(shuō)明:
- 專門用于存放緩存數(shù)據(jù),和內(nèi)部存儲(chǔ)的getCacheDir()相似桐绒。
2.2 Context.getExternalFilesDir(String type)
public static String DIRECTORY_MUSIC = "Music";
String externalFileDir =this.getExternalFilesDir(DIRECTORY_MUSIC).getAbsolutePath();
Log.e("externalFileDir", externalFileDir);
打佣崞ⅰ:
getExternalFilesDir(String type)之拨,type類型你可以根據(jù)自己存儲(chǔ)文件的類型來(lái)定義,會(huì)響應(yīng)的創(chuàng)建出該文件夾咧叭。
說(shuō)明:
- 歸類存放公有文件
- 如果type不為null的話在外部私有目錄下創(chuàng)建返回一個(gè)名為type的文件夾敦锌,為null直接返回外部私有根目錄。如無(wú)特別需要佳簸,個(gè)人的做法是傳入Environment的DIRECTORY常量進(jìn)行文件夾創(chuàng)建。
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());
}
}
打佑北洹:
說(shuō)明:
- 可存放共享媒體文件
- 這個(gè)是在Android 5.0加入的api生均,創(chuàng)建和獲取位于/sdcard/Android/media目錄下的應(yīng)用目錄,該目錄下的文件能夠被其他應(yīng)用訪問(wèn)和被MediaStore查詢和獲取
3. 公有目錄
公有目錄里面的文件是可以被自由訪問(wèn)腥刹,即文件的數(shù)據(jù)對(duì)其他應(yīng)用或者用戶來(lái)說(shuō)都是可以訪問(wèn)的马胧,當(dāng)應(yīng)用被卸載之后,其卸載前創(chuàng)建的文件仍然保留衔峰。
對(duì)于公有目錄上面的文件路徑需要通過(guò)Environment獲取
3.1 getExternalStorageDirectory()
//SD卡外部存儲(chǔ)路徑
String externalStoragePath =Environment.getExternalStorageDirectory().getPath();
Log.e("externalStoragePath", externalStoragePath);
打优寮埂:
3.2 getExternalStoragePublicDirectory(String type)
String eSPublicMusic = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC).getPath();
Log.e("externalStoragePath共享音樂(lè)", eSPublicMusic);
結(jié)果:
說(shuō)明:
- 使用頻率極高的api,返回在根目錄下的名為type的文件夾垫卤,我把它分為兩種用法:一種是傳入Environment的DIRECTORY常量再創(chuàng)建子目錄使用威彰;一種是傳入appPackageName或者易被識(shí)別歸屬的名稱創(chuàng)建子目錄使用。前者會(huì)比較通用穴肘,內(nèi)容可以被各種工具app搜索發(fā)現(xiàn)(包括微信)歇盼;后者算是私用,可以存放不跟隨app生命的文件评抚,即卸載后也可以保留豹缀。
- Environment.DIRECTORY_DCIM是手機(jī)的相冊(cè)。
- Environment.DIRECTORY_PICTURES用于存放各種“正式的”圖片慨代,強(qiáng)烈建議在這里創(chuàng)建文件夾存放你想要被用戶發(fā)現(xiàn)的圖片邢笙,并且微信會(huì)掃描這個(gè)文件夾,讓你的圖片更容易分享侍匙。
- Environment.DIRECTORY_DOWNLOADS可以用于存放app更新的apk等下載資源
4.系統(tǒng)存儲(chǔ)目錄
4.1getRootDirectory()
對(duì)應(yīng)獲取系統(tǒng)分區(qū)根路徑:/system
4.2 getDataDirectory()
對(duì)應(yīng)獲取用戶數(shù)據(jù)目錄路徑:/data
4.3 getDownloadCacheDirectory()
對(duì)應(yīng)獲取用戶緩存目錄路徑:/cache氮惯,
5.清除數(shù)據(jù)和清除緩存的區(qū)別
5.1清除數(shù)據(jù)
清除數(shù)據(jù)清除的是保存在app中所有數(shù)據(jù),就是上面提到的位于packagename下面的所有文件丈积,包含內(nèi)部存儲(chǔ)(/data/data/packagename/)和外部存儲(chǔ)(/storage/emulated/0/Android/data/packagename/)筐骇。當(dāng)然除了SD卡上面的數(shù)據(jù),SD卡上面的數(shù)據(jù)當(dāng)app卸載之后還會(huì)存在的江滨。
5.2清除緩存
緩存是程序運(yùn)行時(shí)的臨時(shí)存儲(chǔ)空間铛纬,它可以存放從網(wǎng)絡(luò)下載的臨時(shí)圖片,從用戶的角度出發(fā)清除緩存對(duì)用戶并沒(méi)有太大的影響唬滑,但是清除緩存后用戶再次使用該APP時(shí)告唆,由于本地緩存已經(jīng)被清理棺弊,所有的數(shù)據(jù)需要重新從網(wǎng)絡(luò)上獲取。為了在清除緩存的時(shí)候能夠正常清除與應(yīng)用相關(guān)的緩存擒悬,請(qǐng)將緩存文件存放在getCacheDir()或者 getExternalCacheDir()路徑下模她。