Android文件系統(tǒng)

內(nèi)部存儲

內(nèi)部存儲主要用于保存應(yīng)用的私有文件,其他應(yīng)用無法訪問這些數(shù)據(jù)。當應(yīng)用卸載的時候,這些數(shù)據(jù)也會被刪除。使用內(nèi)部存儲不需要任何額外權(quán)限。

1.寫入數(shù)據(jù)

FileOutputStream outputStream = context.openFileOutput("filePath", Context.MODE_PRIVATE);

2.讀取數(shù)據(jù)

FileInputStream inputStream = context.openFileInput("filePath");

3.讀取讀取靜態(tài)文件

InputStream inputStream = context.getResources().openRawResource(R.raw.rawfile) ;

注意,在raw文件夾中,文件名只能包含小寫字母、數(shù)字和下劃線。

4.緩存數(shù)據(jù)

File cacheFile = context.getCacheDir();

這個File對象對應(yīng)的就是內(nèi)部存儲中用于保存緩存數(shù)據(jù)的根目錄。
注意,應(yīng)用的私有緩存文件不應(yīng)該過大。如果內(nèi)部存儲空間不足,系統(tǒng)可能會刪除這些緩存文件。為了保證良好的用戶體驗,應(yīng)用應(yīng)該定期主動清除自己的緩存數(shù)據(jù)。

外部存儲

除了內(nèi)部存儲,Android系統(tǒng)還為開發(fā)者提供了外部存儲。外部存儲并不僅僅指SD卡,它可能是可移除的存儲介質(zhì)(典型如SD卡),也可能是不可移除的存儲介質(zhì)(如現(xiàn)在很多一體機內(nèi)置的存儲器)。外部存儲是相對于內(nèi)部存儲的概念,用于保存全局范圍可讀取的文件。這也就意味著,保存在外部存儲中的數(shù)據(jù)可以被設(shè)備中的任何應(yīng)用訪問,甚至也可以被用戶查看、修改。

1.申請權(quán)限

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

如果應(yīng)用同時有讀、寫的需求,只需要申請WRITE_EXTERNAL_STORAGE權(quán)限即可。
注意,Android 6.0(API 23、Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)引入了運行時權(quán)限的概念,以上提到的兩種權(quán)限都需要動態(tài)地獲取。

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
        android:maxSdkVersion="18"/>

在Android 4.4(API 19)及以上,如果只是在外部存儲中讀、寫應(yīng)用的私有文件,就不需要申請這些權(quán)限。因此,我們可以使用maxSdkVersion屬性實現(xiàn)只在較低版本申請權(quán)限,如上所示。

2.Environment中定義的外部存儲狀態(tài)常量:

MEDIA_UNKNOWN:未知狀態(tài)
MEDIA_REMOVED:移除狀態(tài)(外部存儲不存在)
MEDIA_UNMOUNTED:未裝載狀態(tài)(外部存儲存在但是沒有裝載)
MEDIA_CHECKING:磁盤檢測狀態(tài)
MEDIA_NOFS:外部存儲存在,但是磁盤為空或使用了不支持的文件系統(tǒng)
MEDIA_MOUNTED:就緒狀態(tài)(可讀、可寫)
MEDIA_MOUNTED_READ_ONLY:只讀狀態(tài)
MEDIA_SHARED:共享狀態(tài)(外部存儲存在且正通過USB共享數(shù)據(jù))
MEDIA_BAD_REMOVAL:異常移除狀態(tài)(外部存儲還沒有正確卸載就被移除了)
MEDIA_UNMOUNTABLE:不可裝載狀態(tài)(外部存儲存在但是無法被裝載,一般是磁盤的文件系統(tǒng)損壞造成的)

3.外部存儲可寫、可讀

public boolean isExternalStorageWritable() {
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state)) {
        return true;
    }
    return false;
}

4.外部存儲至少可讀

public boolean isExternalStorageReadable() {
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state) ||
        Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
        return true;
    }
    return false;
}

公共文件(共享文件)

對于在應(yīng)用中產(chǎn)生的多媒體類型的文件,如音樂、圖片、鈴聲等,一般應(yīng)該保存在外置存儲中對應(yīng)的公共目錄下,如/Music、/Pictures、/Ringtones,這樣方便和其他的應(yīng)用共享這些文件。同時,系統(tǒng)的媒體掃描器也能正確地對這些文件進行歸類。

1.Environment中定義文件類型的常量:

DIRECTORY_MUSIC:音樂類型
DIRECTORY_PICTURES:圖片類型
DIRECTORY_MOVIES:電影類型
DIRECTORY_DCIM:照片類型
DIRECTORY_DOWNLOADS:下載文件類型
DIRECTORY_DOCUMENTS:文檔類型
DIRECTORY_RINGTONES:鈴聲類型
DIRECTORY_ALARMS:鬧鐘提示音類型
DIRECTORY_NOTIFICATIONS:通知提示音類型
DIRECTORY_PODCASTS:播客音頻類型

2.獲取共享文件目錄

File file = Environment.getExternalStoragePublicDirectory(String type);

注意,返回的文件目錄可能還不存在,因此在執(zhí)行文件操作前應(yīng)該確保相應(yīng)的文件目錄已經(jīng)存在,否則使用File的mkdirs方法創(chuàng)建文件目錄。

小技巧:如果不希望系統(tǒng)的媒體掃描器訪問我們的媒體文件,可以在媒體文件所在的目錄下新建一個名為.nomedia的空文件,這會阻止媒體掃描器歸類我們的文件并提供給其他應(yīng)用。

私有文件

對于應(yīng)用私有的文件,則應(yīng)該使用Context的getExternalFilesDir方法訪問外部存儲中的私有存儲目錄,媒體掃描器不會掃描這些目錄。可以為這個方法傳入一個String類型的type參數(shù),用于獲取私有存儲目錄中相應(yīng)的媒體文件子目錄。當然,也可以傳入null直接獲取私有存儲的根目錄。這個方法的返回值也是一個File對象。

1.Environment中定義文件類型的常量:

DIRECTORY_MUSIC:音樂類型
DIRECTORY_PICTURES:圖片類型
DIRECTORY_MOVIES:電影類型
DIRECTORY_RINGTONES:鈴聲類型
DIRECTORY_ALARMS:鬧鐘提示音類型
DIRECTORY_NOTIFICATIONS:通知提示音類型
DIRECTORY_PODCASTS:播客音頻類型

另外,出于兼容性的考慮,可以使用ContextCompat的getExternalFilesDirs方法。這是一個靜態(tài)方法,返回值也是一個File數(shù)組。在Android 4.4及以上,效果和Context的getExternalFilesDirs方法一致;而在Android 4.3及以下,返回的File數(shù)組始終只包含一個對象。

注意,某些移動設(shè)備可能既提供了內(nèi)置存儲器作為外部存儲空間,同時又提供了SD卡作為外部存儲空間。也就是說,在這些設(shè)備中外部存儲實際上包含了兩塊磁盤。在Android 4.3(API 18)及以下,Context的getExternalFilesDir方法僅僅會返回內(nèi)置存儲器對應(yīng)的外部存儲控件,而無法訪問SD卡對應(yīng)的存儲空間。從Android 4.4(API 19)開始,Context新增了getExternalFilesDirs方法。這個方法的返回值是一個File數(shù)組,包含兩個對象(可能為null),這樣就可以實現(xiàn)對內(nèi)置存儲器和SD卡的訪問。數(shù)組的第一個對象默認是外部主存儲,官方的開發(fā)建議是除非這個位置已滿或不可用,否則應(yīng)該使用這個位置。

注意,當應(yīng)用卸載時,這些私有存儲目錄中的文件也會被刪除。此外,雖然系統(tǒng)的媒體掃描器不會訪問外部存儲中的私有存儲目錄,但是其他具有READ_EXTERNAL_STORAGE或WRITE_EXTERNAL_STORAGE權(quán)限的應(yīng)用依舊可以讀/寫這些私有存儲目錄中的文件。因此對于真正重要的文件,還是應(yīng)該保存在應(yīng)用的內(nèi)部存儲中。
補充:私有文件根目錄的參考路徑:Android/data/包名/files/

緩存文件

在外部存儲中也有專門保存緩存文件的空間,可以通過Context的getExternalCacheDir方法訪問緩存文件目錄,返回值是一個File對象。上文曾說過,外部存儲可能同時包含內(nèi)置存儲器和SD卡兩個存儲空間,因此在Android 4.4(API 19)及以上還可以通過Context的getExternalCacheDirs方法訪問這兩個存儲空間。這個方法會返回一個File數(shù)組,包含兩個對象,第一個對象默認是外部主存儲對應(yīng)的緩存文件目錄。

同樣,為了兼容性,也可以使用ContextCompat的getExternalCacheDirs方法。這是一個靜態(tài)方法,返回值也是一個File數(shù)組。在Android 4.4及以上,效果和Context的getExternalCacheDirs方法一致;而在Android 4.3及以下,返回的File數(shù)組始終只包含一個對象。
注意,當應(yīng)用卸載時,緩存目錄下的文件也會被系統(tǒng)刪除。當然,官方建議開發(fā)者應(yīng)該主動移除不再需要的緩存文件,這有助于節(jié)省存儲空間并保持應(yīng)用性能。
補充:緩存文件根目錄的參考路徑:Android/data/包名/cache/

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