應用中關於資料的持久化儲存,不管是簡單的SharedPreferences還是資料庫SQLiteDatabase,本質上都是將資料儲存到系統的某種型別的檔案中。因此可以直接使用java.io.File檔案類將資料以任意型別存取。
在獲取到File
檔案類的物件後,就可以使用其相關方法執行對檔案的讀寫等相關操作,這部分屬於Java語言開發或Kotlin語言開發的基礎知識,不再多言。而在Android系統上因為各種原因,獲取File
物件的方式有所區別,本文將重點介紹。
這裡需要注意,
File
檔案類不僅可以是一個可讀寫資料的正常檔案,也可以是一個包含上述檔案的資料夾。下文如無特別說明,檔案亦指儲存資料的正常檔案和包含正常檔案的資料夾。
硬體儲存區域
在瞭解資料的檔案儲存之前,當然要先搞清楚Android系統對硬體儲存裝置的劃分規則。
一般裝置所安裝Android系統的分割槽空間,被定義為Android系統的內部儲存空間。通常應用程式的安裝包及安裝後的相關資料檔案,都預設儲存在內部儲存空間中。內部儲存空間為不同應用程式劃分了不同的訪問區間可以操作,而系統使用者是無法正常訪問內部儲存空間的,這有效防止了應用程式間的檔案安全性。
內部儲存的空間往往不會太大,因此不建議應用程式在內部儲存中佔用大量空間。於是Android系統又定義了外部儲存空間,應用程式過大的檔案可儲存在外部儲存中,比如相機應用程式所儲存的照片。同時外部儲存是允許系統使用者訪問的,這也就是檔案管理應用程式所展示的儲存空間。
而在某些硬體裝置中,比如較老版本的移動手機,為了增大硬體儲存空間,還會使用SDcard增加可擴充套件儲存區。這部分儲存同樣屬於系統的外部儲存空間範疇。
在訪問外部儲存時,應用程式需要申請外部儲存的讀寫許可權,包括android.Manifest.permission.READ_EXTERNAL_STORAGE
和android.Manifest.permission.WRITE_EXTERNAL_STORAGE
。
系統級檔案
所謂系統級檔案,就是該類檔案允許系統中的任何應用程式讀寫訪問。其中外部儲存空間中的檔案都是系統級檔案。
目標版本級別小於29的應用程式
在Android10即API 29以前,手機的外接SD卡可以作為系統級檔案使用,在應用程式中,可以藉助android.os.Environment環境類的getExternalStorageDirectory()
系列靜態方法獲取外部儲存中的相關File
檔案,同時使用isExternalStorageEmulated ()
系列靜態方法獲取類似外部儲存是否載入等資訊。
這裡獲取外部儲存根目錄的
Environment.getExternalStorageDirectory()
方法在API29中廢棄,而在API30中替換為Environment.getStorageDirectory()
方法。
目標版本級別等於29的應用程式
從Android10開始,系統引入了分割槽儲存的概念,在開啟了分割槽儲存的應用程式中,只能訪問其應用級檔案和媒體檔案。應用級檔案在下文會有詳細講解。而所謂的媒體檔案是儲存在外部儲存中的,主要包括圖片、音訊、視訊和下載檔案,共四種媒體檔案類。
其中一般圖片儲存路徑為 DCIM/ 和 Picture/ ,並將檔案資訊儲存在MediaStore.Images類定義的相關常量所標記的資料庫中;
音訊儲存路徑為 Alarms/ 、 Audiobooks/、 Music/ 、 Notifications/ 、 Podcasts/ 和 Ringtones/ ,並將檔案資訊儲存在MediaStore.Audio類定義的相關常量所標記的資料庫中;
視訊儲存路徑為 DCIM/ 、 Movies/ 和 Picture/ ,並將檔案資訊儲存在MediaStore.Video類定義的相關常量所標記的資料庫中;
下載檔案儲存路徑為 Download/ ,並將檔案資訊儲存在MediaStore.Downloads類定義的相關常量所標記的資料庫中。
這裡的下載檔案路徑MediaStore.Downloads需要特別注意,其路徑只適用於Android10即API 29及以上的系統上,不管應用程式的目標版本級別為多少,只要在Android9及以下版本中,就無法訪問下載檔案路徑的相關內容。
而且在下載檔案路徑中的檔案,如果由非建立該檔案的應用程式所訪問,只能使用儲存訪問框架呼叫系統檔案選擇器與使用者互動,而不能像另外三種媒體檔案一樣直接程式碼訪問。
分割槽儲存的開啟方式是修改 AndroidManifest.xml 清單檔案,在 <application>
標籤中增加屬性值內容 android:requestLegacyExternalStorage=“false”
,這也是預設設定;反之,如果設定android:requestLegacyExternalStorage=“true”
則是關閉分割槽儲存,官方推薦該配置僅可在檔案相容性適配階段作為過渡使用。
開啟了分割槽儲存的應用程式,在讀寫自己的應用級檔案時,不需要另外申請許可權。但是在訪問媒體檔案時,同樣需要外部儲存的讀寫許可權,包括android.Manifest.permission.READ_EXTERNAL_STORAGE
和android.Manifest.permission.WRITE_EXTERNAL_STORAGE
。
而媒體檔案的訪問方式,是通過上下文環境Context
物件的getContentResolver()
方法,獲取android.content.ContentResolver內容解析類物件,通過該物件可以對Android系統的資料庫進行增刪改查等操作,其用到的相關常量都可以在上文的四種媒體檔案類中查詢。至於ContentResolver
內容解析類的原理和使用方式,將在後面關於應用級檔案共享的文章中詳細講解。
目標版本級別不小於30的應用程式
在Android11及API 30及以上的系統中,強制開啟了分割槽儲存,應用只能訪問其應用級檔案和媒體檔案。同時新增了管理外部儲存的許可權android.Manifest.permission.MANAGE_EXTERNAL_STORAGE
,與上文的外部儲存的讀寫許可權共同授權,允許當前應用程式訪問外部儲存的所有檔案。
而訪問外部儲存的方式同樣是使用Environment
環境類的getStorageDirectory()
系列靜態方法獲取外部儲存中的相關File
檔案。
應用級檔案
所謂應用級檔案,就是該檔案只執行其所屬的應用程式讀寫訪問,只能由該應用程式建立,且隨著應用程式的解除安裝或清除資料而刪除。
在沒有開啟分割槽儲存之前,即Android 10系統版本之前,應用級檔案不僅可以儲存在內部儲存中,也可以儲存在外部儲存中,且由於應用程式之間對外部儲存的訪問並未受到限制,所以外部儲存部分的應用級檔案往往可以被不同應用程式訪問。
而自Android 10啟用分割槽儲存之後,應用程式的應用級檔案只能儲存在內部儲存中,即便在Android 11系統之後恢復了應用程式對外部儲存的訪問授權,也不會在外部儲存中建立應用級檔案。
訪問應用級檔案的方式是通過上下文環境類
android.content.Context物件。
呼叫Context
物件的getDir(String name, int mode)
方法可以獲取指定目錄下的私有檔案,返回File
檔案型別的物件,通常路徑為 /data/data/應用包名/app_name/name。其中引數 name 是指定的檔名;引數 mode 是對該檔案的操作模式,通常為Context.MODE_PRIVATE=0
表示檔案私有,或者Context.MODE_APPEND
為寫入檔案的追加模式。
呼叫Context
物件的getCacheDir()
方法可以獲取當前應用程式下的快取檔案目錄,返回File
檔案型別的物件,通常路徑為 /data/data/應用包名/cache/。
呼叫Context
物件的getFilesDir()
方法可以獲取當前應用程式下的特定檔案目錄,返回File
檔案型別的物件,通常路徑為 /data/data/應用包名/files/。
還有其他相關方法,可以獲取當前應用程式下的某些指定檔案目錄,不再贅述。
對於應用程式下的應用級檔案通常是不允許其他應用訪問的,可如果某些應用級檔案的確想被其他應用程式所訪問,比如某個通訊類應用程式需要訪問通訊錄應用中的聯絡人資訊,有什麼好的辦法呢?敬請關注下一章瞭解詳情。