Android 內部存儲/外部存儲 及 讀寫權限

摘要

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

  1. 內部存儲的文件是應用的私有文件,其他應用不能訪問。
  2. 應用訪問自己的內部存儲不需要權限,訪問外部存儲需要申請權限。
  3. 應用卸載后,這些文件也會被移除。

獲取內部存儲的方式如下:

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 種

  1. MODE_PRIVATE,設為私有文件
  2. MODE_APPEND,openFileOutput,文件存在則追加內容
  3. MODE_WORLD_READABLE,API 17 廢棄
  4. 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以后 外部存儲(私有目錄) 不需要

外部存儲 - 私有目錄

  1. 屬于應用私有,但是這些私有數據可以被其他應用訪問和修改(通過私有目錄的地址)
  2. 應用卸載時,此目錄及其內容將被刪除。
  3. 系統媒體掃描程序不會讀取這些目錄的文件,因此不能從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

外部存儲注意事項

  1. 使用前先檢查文件狀態
    外部存儲的文件,所有的應用和用戶都能移除和修改這些權限。
    在使用外部存儲執行工作之前,應該使用 getExternalStorageState() 檢查介質是否可用,介質可能已經裝載到設備,處于缺失、只讀或其他某種狀態。

檢查可用性的方法:

String status = Environment.getExternalStorageState();
boolean mounted = status.equals(Environment.MEDIA_MOUNTED)
                    || status.equals(Environment.MEDIA_MOUNTED_READ_ONLY);
return mounted;
  1. 對于支持外插SD卡的設備,外部存儲包括兩部分:內置存儲卡和外置SD卡;

Android 4.3 以下,只能通過Context#getExternalFilesDir(type) 來獲取外部存儲在內置存儲卡分區的私有目錄,無法獲取外置SD卡。

Android 4.3 開始,可以通過Context#getExternalFilesDirs(type) 獲取一個File數組,包含了內置存儲卡分區和外置SD的私有目錄地址。

可以使用兼容庫的靜態方法 ContextCompate.getExternalFilesDirs() 兼容 4.3。

總結

  1. 應用使用內部存儲不需要權限,內部存儲屬于應用的私有存儲區域,其他應用不可訪問,但應用卸載,內部存儲中對應的文件也會刪除。
  2. 外部存儲分為公共目錄和私有目錄,外部存儲是可以全局訪問的,但需要申請讀寫權限。Android4.4以后私有目錄不需要申請讀寫權限。
  3. 如果緩存的數據量較大,請不要保存到內部存儲中。
  4. 如果想保存可共享給其他應用的數據,請保存到外部存儲公共目錄中。
  5. clear data 和 clear cache 兩個都是應用的緩存數據,清理的是外部存儲中的私有目錄下的files/cache,即 /storage/emulated/0/Android/data/com.sankuai.meituan/cache

參考資料

感謝以下文章作者
解析Android內部存儲、外部存儲的區別

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。