Android 的儲(chǔ)存方式

open.weixin.qq.com/connect/oauth2/authorize (引用的文章地址)

方便以后查找才復(fù)制文章

前言

這篇文章解析 Android 設(shè)備上數(shù)據(jù)持久化存儲(chǔ)方式,數(shù)據(jù)存儲(chǔ)方式包括共享首選項(xiàng)、內(nèi)部存儲(chǔ)、外部存儲(chǔ)、SQLite 數(shù)據(jù)庫(kù)、網(wǎng)絡(luò)連接五種存儲(chǔ)方式,方式的選取取決于使用者的需求,如果對(duì)持久化存儲(chǔ)方式不了解,那么一定會(huì)有這么幾個(gè)疑問(wèn):

清理緩存,清理的是哪里?

清理數(shù)據(jù),清理的是哪里?

應(yīng)用私有文件放在哪里?

公共文件存放在哪里?

如果你對(duì)以上存在疑問(wèn),那么看完本章后相信可以解開你的疑惑,還會(huì)加深對(duì)數(shù)據(jù)持久化存儲(chǔ)的理解。

準(zhǔn)備知識(shí)

理解 Android 系統(tǒng)中的內(nèi)部存儲(chǔ)和外部存儲(chǔ)空間的區(qū)別,通過(guò) Android Studio3.0 Device File Explorer 查看 Android 手機(jī)頂級(jí)系統(tǒng)目錄


關(guān)注 data 和 storage 目錄,內(nèi)部存儲(chǔ)空間指的是 data目錄,外部存儲(chǔ)空間指的是 storage目錄,下面來(lái)細(xì)說(shuō)這兩個(gè)目錄:


data 目錄內(nèi)主要目錄是由存放所有應(yīng)用數(shù)據(jù)的 data目錄和存放所有應(yīng)用程序的 app 目錄組成。安裝應(yīng)用的時(shí)候是把 APK 數(shù)據(jù)提取到 app 目錄內(nèi),而 data目錄是 app 目錄內(nèi)應(yīng)用產(chǎn)生數(shù)據(jù)的存放處,各個(gè)應(yīng)用數(shù)據(jù)以包名分割開,該 data 目錄是內(nèi)部存儲(chǔ)私有目錄,內(nèi)容會(huì)隨著應(yīng)用卸載而清除。

應(yīng)用內(nèi)部存儲(chǔ)空間內(nèi)會(huì)有以下幾個(gè)常見目錄:

/data/data/包名/shared_prefs

/data/data/包名/databses

/data/data/包名/files

/data/data/包名/cache

shared_prefs 是 SharedPreference 創(chuàng)建的文件;databases是數(shù)據(jù)庫(kù)創(chuàng)建的文件;files 存放應(yīng)用創(chuàng)建文件;cache 存儲(chǔ)臨時(shí)緩存文件,這些目錄都是應(yīng)用私有目錄。

那么如何獲取私有目錄,因?yàn)楹蛻?yīng)用相關(guān),所以私有目錄通過(guò) context 對(duì)象獲取,以下目錄都屬于內(nèi)部存儲(chǔ)私有目錄:

getCacheDir()

獲取緩存目錄。該目錄用于緩存臨時(shí)數(shù)據(jù),不能永久存儲(chǔ)數(shù)據(jù),因?yàn)楫?dāng)設(shè)備的內(nèi)部存儲(chǔ)空間不足時(shí),Android 系統(tǒng)會(huì)刪除這些緩存文件以回收空間。為了 APP 高效管理存儲(chǔ)空間,應(yīng)該自行維護(hù)文件,不應(yīng)該依賴系統(tǒng)來(lái)清理。系統(tǒng)應(yīng)用管理點(diǎn)擊清除緩存的時(shí)候,私有目錄內(nèi)只有緩存目錄的數(shù)據(jù)會(huì)被清除,如果點(diǎn)擊的是清除數(shù)據(jù),那么私有目錄內(nèi)即包名下的所有文件都會(huì)被清除。該目錄對(duì)其他或者用戶不可見,敏感數(shù)據(jù)應(yīng)該存放在此目錄下。

getDir(String name, int mode)

在內(nèi)部私有根目錄下(包名下)創(chuàng)建 name目錄,目錄名稱任意字符串,函數(shù)返回 File 對(duì)象,如果name目錄不存在會(huì)創(chuàng)建目錄。

getFilesDir()

獲取存放文件的目錄,該目錄可以存放持久文件,只要應(yīng)用不卸載。

openFileOutput(String name, int mode)

在 getFilesDir() 下打開或創(chuàng)建文件,如果存在則打開,不存在則創(chuàng)建新文件,可以通過(guò)write() 方法寫入文件,文件存儲(chǔ)在 getFilesDir() 目錄內(nèi)。

openFileInput(String name)

打開指定文件,如果文件存在則返回 FileInputStream 對(duì)象,操作對(duì)象可以讀取文件內(nèi)容,文件不存在拋出 FileNotFoundException 異常。

storage 目錄是外部存儲(chǔ)目錄。外部存儲(chǔ)可以是可移除存儲(chǔ)介質(zhì)(SD卡)或內(nèi)部存儲(chǔ)(不可移除),通過(guò)文件管理器看到的都是外部存儲(chǔ)目錄,外部存儲(chǔ)目錄又分為公有目錄和私有目錄。外部存儲(chǔ)公有目錄下的文件所有應(yīng)用都有訪問(wèn)、修改、刪除權(quán)限,應(yīng)用的卸載不會(huì)影響公有目錄文件,應(yīng)用訪問(wèn)公有目錄需要申請(qǐng)權(quán)限;私有目錄默認(rèn)僅供應(yīng)用本身訪問(wèn),不需要申請(qǐng)權(quán)限,可以讀取/寫入內(nèi)容;如果訪問(wèn)非私有目錄,需要申請(qǐng)文件權(quán)限。應(yīng)用卸載后,私有目錄和內(nèi)容將全部被清除,下面介紹這兩個(gè)目錄如何獲?。?/p>

公有目錄獲取

公有目錄與 Context 無(wú)關(guān),使用 Environment 獲取

Environment.getExternalStoragePublicDirectory(Stringtype)

如果要獲取公有根目錄使用無(wú)參數(shù)函數(shù)獲取,如下:

Environment.getExternalStoragePublicDirectory()

以下type是公有文件常見的存儲(chǔ)位置

Environment.DIRECTORY_PICTURES 圖片目錄

Environment.DIRECTORY_DCIM 相冊(cè)目錄

Environment.DIRECTORY_DOCUMENTS 文檔目錄

Environment.DIRECTORY_DOWNLOADS 下載目錄

Environment.DIRECTORY_MOVIES 視頻

私有目錄獲取

私有目錄和 Context 相關(guān),所以使用 context.getExternalXXX 獲取目錄,以下目錄范圍都屬于外部存儲(chǔ)私有目錄內(nèi):

getExternalFilesDirs() 獲取文件根目錄,應(yīng)用不卸載,可以長(zhǎng)期存放文件。

getExternalFilesDirs(int type) 獲取文件內(nèi)的具體目錄。通過(guò) type 參數(shù)指定,type 類型和公有目錄類型一致

getExternalCacheDir() 獲取緩存目錄。該目錄用于存放臨時(shí)私有文件,如果系統(tǒng)應(yīng)用管理內(nèi)點(diǎn)擊清除緩存,那么該目錄下所有內(nèi)容被清除,如果點(diǎn)擊的是清除數(shù)據(jù),那么整個(gè)私有目錄(包名)和內(nèi)容都會(huì)被清除。

getExternalMediaDirs() 獲取應(yīng)用存放媒體目錄。目錄內(nèi)的內(nèi)容可以被其他應(yīng)用訪問(wèn),通過(guò) MediaStore 可以查詢和獲取。 再普及一個(gè)小知識(shí),在 Android6.0 及以上版本中來(lái)看兩個(gè)絕對(duì)路徑:

/data/data/com.example.interviewroad/shared_prefs

/data/user/0/com.example.interviewroad/shared_prefs

這兩條絕對(duì)路徑指向同一個(gè)文件。這是因?yàn)?Android 6.0 支持多用戶,文件的實(shí)際路徑是 /data/user/0/XXX(0代表的用戶ID),而 /data/data/XXX 是為了方便查看數(shù)據(jù)而創(chuàng)建的引用目錄,實(shí)際指向 /data/user/0/XXX,下文有時(shí)會(huì)出現(xiàn) /data/data/XXX 和 /data/user/0/XXX表述的是一樣的意思,如果是 Android 5.0 及以下版本,返回的是 /data/data/XXX, 這下完全明白了。

把準(zhǔn)備知識(shí)看懂了,前言中提到的問(wèn)題可以輕松解決。下面開始解析Android數(shù)據(jù)持久化的方式。

共享首選項(xiàng)

共享首選項(xiàng)這個(gè)名字聽起來(lái)有點(diǎn)陌生,其實(shí)是 SharedPreference 類,Android 中文網(wǎng)官網(wǎng)這么翻譯,我覺(jué)得以后要習(xí)慣這叫法,具體用法相信大家已經(jīng)非常熟就不造輪子了,來(lái)看一段代碼

privatevoidstoreSharedPreferences(){SharedPreferencessharedPreferences=getSharedPreferences("My_Pref_File",Context.MODE_PRIVATE);SharedPreferences.Editoredit=sharedPreferences.edit();edit.putBoolean("silentMode",true);edit.commit();}

這段代碼會(huì)在 Android 設(shè)備上創(chuàng)建 My_Pref_File.xml 文件,文件內(nèi)存放了一對(duì)布爾類型的鍵值對(duì),鍵為 silentMode,值為true。My_Pref_File.xml 文件存放在內(nèi)部存儲(chǔ)空間內(nèi),來(lái)看一張截圖,這張圖是通過(guò) Android Studio3.0 新增特性 Device File Explorer 查看


My_Pref_File.xml 文件位于 /data/user/0/com.example.interviewroad/shared_prefs 目錄下,該目錄屬于內(nèi)部存儲(chǔ)空間,所以SharedPreference類創(chuàng)建的文件所在目錄位于/data/user/0/包名/shared_prefs/目錄下,位于內(nèi)部存儲(chǔ)私有目錄下。

使用內(nèi)部存儲(chǔ)

1、內(nèi)部存儲(chǔ)保存文件:

使用 openFileOutput(String name, int mode) 函數(shù),返回 FileOutputStream 對(duì)象。

調(diào)用 FileOutputStream 對(duì)象的 write() 函數(shù)。

關(guān)閉流對(duì)象,調(diào)用 close() 方法。

讀取使用 openFileInput(String name),使用完后也要關(guān)閉流對(duì)象。

如果需要讀取 /res/raw/ 下的文件,使用 getResources().openRawResource(X),X 為資源 ID 即 R.raw.,返回InputStream對(duì)象。

代碼如下:

StringFILENAME="hello_file";

Stringstring="hello world!";

FileOutputStreamfos=openFileOutput(FILENAME,Context.MODE_PRIVATE);

fos.write(string.getBytes());

fos.close();

以上代碼會(huì)創(chuàng)建 hello_file 文件,文件存放在 /data/data/包名/files 目錄下,使用 context.getFilesDir() 獲取。

2、內(nèi)部存儲(chǔ)內(nèi)放緩存文件:

主要用于緩存數(shù)據(jù),而不是持久化數(shù)據(jù),通過(guò) getCacheDir() 獲取緩存目錄,該目錄僅供于存放臨時(shí)文件,應(yīng)用清除緩存時(shí),會(huì)清理該目錄,詳細(xì)說(shuō)明也在準(zhǔn)備知識(shí)中講到。

使用外部存儲(chǔ)

1、權(quán)限申請(qǐng)

訪問(wèn)外部存儲(chǔ)上的文件,必須申請(qǐng) READ_EXTERNAL_STORAGE 或 WRITE_EXTERNAL_STORAGE 權(quán)限。


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


如果需要讀/寫權(quán)限,只需要申請(qǐng) WRITE_EXTERNAL_STORAGE,內(nèi)包含讀取權(quán)限。

2、檢查存儲(chǔ)介質(zhì)可用性

由于外部存儲(chǔ)介質(zhì)可能處于卸載、可讀或其他狀態(tài),所以在使用之前一定要調(diào)用 getExternalStorageState() 檢查存儲(chǔ)介質(zhì)是否可用,代碼如下:

publicbooleanisExternalStorageWritable(){

Stringstate=Environment.getExternalStorageState();

if(Environment.MEDIA_MOUNTED.equals(state)){

returntrue;

}

returnfalse;

}

3、保存公有文件

如果應(yīng)用保存的文件需要供給其他應(yīng)用或者用戶訪問(wèn),那么文件應(yīng)該存放在公有目錄,如果私有目錄文件或數(shù)據(jù)庫(kù)需要共享,那么要使用自定義 ContentProvider。公有目錄在準(zhǔn)備知識(shí)中已經(jīng)介紹了,根據(jù)數(shù)據(jù)的類型保存到對(duì)應(yīng)的目錄,比如圖片保存在 Pictures/、 音樂(lè)保存在 Music/、下載文件保存在 Download/ 等,按類別保存到對(duì)應(yīng)的目錄,系統(tǒng)媒體掃描程序會(huì)將文件歸類,而這些目錄獲取通過(guò)以下目錄

Environment.getExternalStoragePublicDirectory(Stringtype)

來(lái)看一段代碼,獲取圖片公有目錄,并在內(nèi)部創(chuàng)建 albumName 文件夾

publicFilegetAlbumStorageDir(StringalbumName{

Filefile=newFile(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),albumName);if(!file.mkdirs()){Log.e(LOG_TAG,"創(chuàng)建失敗");

}

returnfile;

}

4、保存私有文件

調(diào)用 getExternalFilesDir(String type) 將數(shù)據(jù)保存在外部存儲(chǔ)的私有存儲(chǔ)目錄下。需要將文件保存至合適目錄,可以通過(guò) type 指定目錄類型,具體類型參考準(zhǔn)備知識(shí)部分。

從 Android 4.4 開始如果僅僅讀取或?qū)懭胨接形募?,則不需要文件讀寫權(quán)限,如果需要兼容低版本,可以通過(guò)添加 maxSdkVersion 屬性來(lái)聲明,只在較低版本上使用權(quán)限,來(lái)看代碼:

當(dāng)卸載應(yīng)用時(shí),此目錄下的所有文件將被清除。

5、外部存儲(chǔ)空間上保存緩存文件

要將文件緩存在外部存儲(chǔ)上,需要用 getExternalCacheDir() 訪問(wèn),該目錄是私有目錄。同樣該目錄會(huì)隨著應(yīng)用卸載而清除,且清理緩存文件時(shí)也會(huì)清理該目錄。應(yīng)用提高 app 性能和穩(wěn)定性,應(yīng)當(dāng)自行維護(hù)緩存目錄的大小,而不能依賴系統(tǒng)。這里建議使用 ContextCompat.getExternalCacheDir() 訪問(wèn),增強(qiáng)向下兼容性。

使用數(shù)據(jù)庫(kù)

Android 系統(tǒng)提供對(duì) SQLite 數(shù)據(jù)庫(kù)的完全支持,在應(yīng)用開發(fā)中,根據(jù)自己需求,使用數(shù)據(jù)庫(kù),比如需要存儲(chǔ)復(fù)雜關(guān)聯(lián)關(guān)系數(shù)據(jù),存放安全數(shù)據(jù)等。

使用網(wǎng)絡(luò)

將數(shù)據(jù)保存在云端。

總結(jié):

如果敏感數(shù)據(jù)或者不被其他應(yīng)用訪問(wèn)的數(shù)據(jù)存放在內(nèi)部存儲(chǔ)私有目錄 ,非隱私數(shù)據(jù)可存放在外部存儲(chǔ)私有目錄或者公有目錄下。

公有文件存放在外部存儲(chǔ) getExternalStoragePublicDirectory 目錄下,不同的文件類型通過(guò) type 指定存放到對(duì)應(yīng)的目錄,好讓系統(tǒng)的媒體掃描程序可以在系統(tǒng)中正確地歸類您的文件。

公有目錄文件的讀寫操作需要申請(qǐng)文件讀寫權(quán)限;自身應(yīng)用訪問(wèn)外部存儲(chǔ)私有目錄 Android 4.4 以及更高版本不需要申請(qǐng)文件讀寫權(quán)限,低于 4.4 需要申請(qǐng)權(quán)限;自身應(yīng)用訪問(wèn)內(nèi)部存儲(chǔ)私有目錄不需要申請(qǐng)文件讀寫權(quán)限;訪問(wèn)其他應(yīng)用外部存儲(chǔ)私有目錄需要申請(qǐng)文件讀寫權(quán)限。

系統(tǒng)清理緩存的時(shí)候,內(nèi)部存儲(chǔ)私有目錄 cache下的所有文件和外部存儲(chǔ)私有目錄 cache 下所有文件將被清除;系統(tǒng)清理數(shù)據(jù)的時(shí)候,內(nèi)部存儲(chǔ)私有目錄和外部程序私有目錄下所有內(nèi)容將被清理。

使用外部存儲(chǔ)時(shí)要檢查外部存儲(chǔ)介質(zhì)是否存在。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)載:http://m.itdecent.cn/p/ebca517ae7d5http://blog.csdn....
    ALEXIRC閱讀 19,784評(píng)論 11 23
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,695評(píng)論 19 139
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,324評(píng)論 25 708
  • 一一情人節(jié)給友禮物 年華遠(yuǎn)行 歲月流淌 當(dāng)年齡已走過(guò)花期 當(dāng)時(shí)間抹去了容顏 當(dāng)歲月畫鬢已如霜 當(dāng)你眼角潛游魚尾 這...
    旖旎i閱讀 143評(píng)論 0 1
  • 感賞我每天有很多充裕的時(shí)間,做自己喜歡的事。 感賞我們之間和平相處,相互體諒。 感賞緣分讓我們認(rèn)識(shí)相互吸引。 感賞...
    張?jiān)?/span>閱讀 172評(píng)論 0 0

友情鏈接更多精彩內(nèi)容