摘要
Android 使用 VFS (Virtual File System) 虛擬文件系統。VFS提供了供存儲設備掛載的節點,同一存儲設備經過分區后,不同的分區可以掛載到不同的節點上,如手機的內置存儲卡。
關鍵字
內置存儲卡 / 外置SD卡
內部存儲 / 外部存儲
目錄結構
VFS 的目錄以 /
為根節點,根節點下面又有不同的節點。物理存儲設備就是掛載到這些節點上。
-
/data/data
該節點是用戶應用的安裝目錄,如百度地圖的安裝路徑是 /data/data/com.baidu.com,該目錄需要root權限 -
/system
該節點是系統應用的安裝目錄 -
/storage
該節點是內置存儲卡和外置SD卡的掛載點
外置SD卡掛載節點:/storage/sdcard1
內置存儲卡掛載節點:/storage/emulated/0
不同的設備掛載節點不同,有的可能在 /mnt下
內部存儲和外部存儲
內部存儲卡/外置SD卡
≠ 內部存儲/外部存儲
首先明確,內置存儲卡/外置SD卡 是在物理層面相對于手機大眾用戶來說的。
外置SD卡:可手動插拔的SD卡。
內置存儲卡:焊接在手機內部不可拆卸的存儲卡。
而,內部存 /外部存儲 是在文件系統邏輯層面相對于開發者來說的,指具體的路徑。
一般針對某個應用而言的,屬于該應用的存儲路徑叫內部存儲,反之為外部存儲。
內部存儲
路徑:/data/data/package_name
/data/data/
下都是已安裝應用的目錄,該目錄下包含的文件都是以包名作為文件名的目錄,例如/data/data/com.sankuai.meituan
- 內部存儲的文件是應用的私有文件,其他應用不能訪問。
- 應用訪問自己的內部存儲不需要權限,訪問外部存儲需要申請權限。
- 應用卸載后,這些文件也會被移除。
獲取內部存儲的方式如下:
Context
File getDir(String name, String mode) ;
// /data/data/com.sankuai.meituan
File getFilesDir();
// /data/data/com.sankuai.meituan/files
File getCacheDir()
// /data/data/com.sankuai.meituan/cache
String getApplicationInfo().dataDir;
// /data/data/com.sankuai.meituan
其中,參數 mode
指創建模式,一種 4 種
-
MODE_PRIVATE
,設為私有文件 -
MODE_APPEND
,openFileOutput,文件存在則追加內容 -
MODE_WORLD_READABLE
,API 17 廢棄 -
MODE_WORLD_WRITEABLE
,API 17 廢棄
注意: Android 7.0 以上android.os.Build.VERSION.SDK_INT>=Build.VERSION_CODES.N
使用3/4 常量時,將會導致SecurityException,這意味著不能通過名稱共享私有文件。
嘗試共享 file://URI
URI將會導致FileUriExposedException,StrictMode API政策禁止在您的應用外部公開file://URL。如果您的應用需要與其他應用共享私有文件,則可以使用 FileProvider 與 FLAG_GRANT_READ_URI_PERMISSION 配合使用。Android 7.0 行為變更 通過FileProvider在應用間共享文件吧
外部存儲
外部存儲,可以是 外置SD卡 或 內置存儲卡的部分分區。
外部存儲,分為 公共目錄 和 私有目錄
版本 | 存儲位置 | 是否需要讀寫權限 |
---|---|---|
Android 4.4以前 | 外部存儲(公共目錄和私有目錄) | 需要 |
Android 4.4以后 | 外部存儲(公共目錄) | 需要 |
Android 4.4以后 | 外部存儲(私有目錄) | 不需要 |
外部存儲 - 私有目錄
- 屬于應用私有,但是這些私有數據可以被其他應用訪問和修改(通過私有目錄的地址)
- 應用卸載時,此目錄及其內容將被刪除。
- 系統媒體掃描程序不會讀取這些目錄的文件,因此不能從MediaStore內容提供程序訪問這些文件
獲取方式
Context
File getExternalCacheDir()
// /storage/emulated/0/Android/data/com.sankuai.meituan/cache
File getExternalFilesDir(String type)
// /storage/emulated/0/Android/data/com.sankuai.meituan/files
外部存儲注意事項
- 使用前先檢查文件狀態
外部存儲的文件,所有的應用和用戶都能移除和修改這些權限。
在使用外部存儲執行工作之前,應該使用 getExternalStorageState() 檢查介質是否可用,介質可能已經裝載到設備,處于缺失、只讀或其他某種狀態。
檢查可用性的方法:
String status = Environment.getExternalStorageState();
boolean mounted = status.equals(Environment.MEDIA_MOUNTED)
|| status.equals(Environment.MEDIA_MOUNTED_READ_ONLY);
return mounted;
- 對于支持外插SD卡的設備,外部存儲包括兩部分:內置存儲卡和外置SD卡;
Android 4.3 以下,只能通過Context#getExternalFilesDir(type)
來獲取外部存儲在內置存儲卡分區的私有目錄,無法獲取外置SD卡。
Android 4.3 開始,可以通過Context#getExternalFilesDirs(type)
獲取一個File數組,包含了內置存儲卡分區和外置SD的私有目錄地址。
可以使用兼容庫的靜態方法 ContextCompate.getExternalFilesDirs() 兼容 4.3。
總結
- 應用使用內部存儲不需要權限,內部存儲屬于應用的私有存儲區域,其他應用不可訪問,但應用卸載,內部存儲中對應的文件也會刪除。
- 外部存儲分為公共目錄和私有目錄,外部存儲是可以全局訪問的,但需要申請讀寫權限。Android4.4以后私有目錄不需要申請讀寫權限。
- 如果緩存的數據量較大,請不要保存到內部存儲中。
- 如果想保存可共享給其他應用的數據,請保存到外部存儲的公共目錄中。
- clear data 和 clear cache 兩個都是應用的緩存數據,清理的是外部存儲中的私有目錄下的files/cache,即 /storage/emulated/0/Android/data/com.sankuai.meituan/cache
參考資料
感謝以下文章作者
解析Android內部存儲、外部存儲的區別