前言
前兩天因為開發一個app更新的功能,我將從伺服器下載的apk檔案放在了內部儲存目錄(測試手機為小米,路徑為:data/user/0/packagename/files)下面,然後安裝的時候一直安裝不了,提示解析包出錯。後來查詢發現,安裝apk是呼叫了PackageInstaller,沒有相關許可權,這個無法獲取內部路徑,所以會安裝不了。藉機也複習了一遍Android下面儲存相關的知識點,特來總結一番。
儲存分類
對於Android儲存目錄,我總結成一張思維導圖,如果有需要原圖的,請在我的公眾號後臺回覆 015 即可獲取原圖。上面這張圖很清楚的展示了Android儲存的目錄,接下來我們詳細分析每一個目錄。內部儲存
內部儲存位於系統中很特殊的一個位置,對於裝置中每一個安裝的 App,系統都會在 data/data/packagename/xxx 自動建立與之對應的資料夾。如果你想將檔案儲存於內部儲存中,那麼檔案預設只能被你的應用訪問到,且一個應用所建立的所有檔案都在和應用包名相同的目錄下。也就是說應用建立於內部儲存的檔案,與這個應用是關聯起來的。當一個應用解除安裝之後,內部儲存中的這些檔案也被刪除。對於這個內部目錄,使用者是無法訪問的,除非獲取root許可權。
String fileDir = this.getFilesDir().getAbsolutePath();
String cacheDir = this.getCacheDir().getAbsolutePath();
複製程式碼
一般情況下,我們獲取到的路徑為data/data/packagename/xxx,小米手機下面列印出來的結果如下:
對於內部儲存路徑,我們一般通過以下兩種方式獲取,內部儲存空間的獲取都需要使用Context:
context.getFileDir()
對應內部儲存的路徑為: data/data/packagename/files,但是對於有的手機如:華為,小米等獲取到的路徑為:data/user/0/packagename/files
context.getCacheDir()
對應內部儲存的路徑為: data/data/packagename/cache,但是對於有的手機如:華為,小米等獲取到的路徑為:data/user/0/packagename/cache應用程式的快取目錄,該目錄內的檔案在裝置記憶體不足時會優先被刪除掉,所以存放在這裡的檔案是沒有任何保障的,可能會隨時丟掉。
外部儲存
針對於外部儲存比較容易混淆,因為在Android4.4以前,手機機身儲存就叫內部儲存,插入的SD卡就是外部儲存,但是在Android4.4以後的話,就目前而言,現在的手機自帶的儲存就很大,現在Android10.0的話,有的手機能達到256G的儲存,針對於這種情況,手機機身自帶的儲存也是外部儲存,如果再插入SD卡的話也叫外部儲存,因此對於外部儲存分為兩部分:SD卡和擴充套件卡記憶體
我們通過一段程式碼來獲取手機的外部儲存目錄,我們用的測試手機是三星G4,帶有插入SD卡的:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
File[] files = getExternalFilesDirs(Environment.MEDIA_MOUNTED);
for (File file : files) {
Log.e("file_dir", file.getAbsolutePath());
}
}
複製程式碼
對於以上程式碼,列印的結果如下:
列印出兩行目錄,第一行目錄是機身自帶的外部儲存目錄,目錄結構為:/storage/emulated/0/Android/data/packagename/files 第二行是儲存卡的目錄結構,路徑為:/storage/extSdCard/Android/data/packagename/files擴充套件外部儲存
此目錄路徑需要通過context來獲取,同時在app解除安裝之後,這些檔案也會被刪除。類似於內部儲存。
getExternalCacheDir()
對應外部儲存路徑:/storage/emulated/0/Android/data/packagename/cache
getExternalFilesDir(String type)
對應外部儲存路徑:/storage/emulated/0/Android/data/packagename/files
SD卡儲存
SD卡里面的檔案是可以被自由訪問,即檔案的資料對其他應用或者使用者來說都是可以訪問的,當應用被解除安裝之後,其解除安裝前建立的檔案仍然保留。
對於SD卡上面的檔案路徑需要通過Environment獲取,同時在獲取前需要判斷SD的狀態:
MEDIA_UNKNOWN SD卡未知
MEDIA_REMOVED SD卡移除
MEDIA_UNMOUNTED SD卡未安裝
MEDIA_CHECKING SD卡檢查中,剛裝上SD卡時
MEDIA_NOFS SD卡為空白或正在使用不受支援的檔案系統
MEDIA_MOUNTED SD卡安裝
MEDIA_MOUNTED_READ_ONLY SD卡安裝但是隻讀
MEDIA_SHARED SD卡共享
MEDIA_BAD_REMOVAL SD卡移除錯誤
MEDIA_UNMOUNTABLE 存在SD卡但是不能掛載,例如發生在介質損壞
String externalStorageState = Environment.getExternalStorageState();
if (externalStorageState.equals(Environment.MEDIA_MOUNTED)){
//sd卡已經安裝,可以進行相關檔案操作
}
複製程式碼
getExternalStorageDirectory()
對應外部儲存路徑:/storage/emulated/0
getExternalStoragePublicDirectory(String type)
獲取外部儲存的共享資料夾路徑如:
DIRECTORY_MUSIC 音樂目錄
DIRECTORY_PICTURES 圖片目錄
DIRECTORY_MOVIES 電影目錄
DIRECTORY_DOWNLOADS 下載目錄
DIRECTORY_DCIM 相機拍照或錄影檔案的儲存目錄
DIRECTORY_DOCUMENTS 檔案文件目錄
String externalStoragePublicDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getPath();
複製程式碼
以上便是獲取相機DCIM目錄,對應獲取的路徑為:/storage/emulated/0/DCIM。
系統儲存目錄
getRootDirectory()
對應獲取系統分割槽根路徑:/system
getDataDirectory()
對應獲取使用者資料目錄路徑:/data
getDownloadCacheDirectory()
對應獲取使用者快取目錄路徑:/cache
相關概念區別
getFileDir()和getCacheDir()區別
這兩個都位於內部儲存目錄/data/data/packagename/下面,位於同一級別,前者是file目錄下面,後面是cache目錄下。
getFileDir()和getExternalFilesDir(String type)區別
前者位於內部儲存目錄/data/data/packagename/file下面,後者位於外部儲存目錄/storage/emulated/0/Android/data/packagename/files下面,它們都存在於應用包名下面,也就是說屬於app應用的,所以當app解除安裝後,它們也會被刪除的。
對於前面提到的app下載升級功能,我們從伺服器端下載的app需要放到外部儲存目錄下面,而不是內部儲存目錄,因為內部儲存目錄的空間很小。另外我也做了相關測試,如果將apk放到內部儲存目錄file下面的話,安裝時會出現問題,提示解析包出錯。
清除資料和清除快取的區別
在app中有清除資料和清除快取這兩個概念,那麼這兩者分別清除的是什麼目錄下面的資料呢?
清除資料
清除資料清除的是儲存在app中所有資料,就是上面提到的位於packagename下面的所有檔案,包含內部儲存(/data/data/packagename/)和外部儲存(/storage/emulated/0/Android/data/packagename/)。當然除了SD卡上面的資料,SD卡上面的資料當app解除安裝之後還會存在的。
清除快取
快取是程式執行時的臨時儲存空間,它可以存放從網路下載的臨時圖片,從使用者的角度出發清除快取對使用者並沒有太大的影響,但是清除快取後使用者再次使用該APP時,由於本地快取已經被清理,所有的資料需要重新從網路上獲取。為了在清除快取的時候能夠正常清除與應用相關的快取,請將快取檔案存放在getCacheDir()或者 getExternalCacheDir()路徑下。
以上便是Android系統中管儲存目錄的一些知識。
關於作者
專注於 Android 開發多年,喜歡寫 blog 記錄總結學習經驗,blog 同步更新於本人的公眾號,歡迎大家關注,一起交流學習~