詳解Android文件存儲(chǔ)
摘要
其實(shí)安卓文件的操作和java在pc環(huán)境下的操作并無二致,之所以需要單獨(dú)講解是因?yàn)榘沧肯到y(tǒng)提供了不同于pc的訪問文件系統(tǒng)根路徑的api,同時(shí)對(duì)一個(gè)應(yīng)用的私有文件做了統(tǒng)一的管理。根據(jù)我的經(jīng)驗(yàn),初學(xué)者在這部分感到很容易混淆內(nèi)部存儲(chǔ)和外部存儲(chǔ)兩個(gè)概念。
其實(shí)安卓文件的操作和java在pc環(huán)境下的操作并無二致,之所以需要單獨(dú)講解是因?yàn)榘沧肯到y(tǒng)提供了不同于pc的訪問文件系統(tǒng)根路徑的api,同時(shí)對(duì)一個(gè)應(yīng)用的私有文件做了統(tǒng)一的管理。根據(jù)我的經(jīng)驗(yàn),初學(xué)者在這部分感到很容易混淆內(nèi)部存儲(chǔ)和外部存儲(chǔ)兩個(gè)概念。
相對(duì)路徑和絕對(duì)路徑
在java中,關(guān)于相對(duì)路徑和絕對(duì)路徑是這樣解釋的,如果你很熟悉這部分以下灰色文字可以跳過:
絕對(duì)路徑是指書寫文件的完整路徑,例如d:\java\Hello.java,該路徑中包含文件的完整路徑d:\java以及文件的全名Hello.java。使用該路徑可以唯一的找到一個(gè)文件,不會(huì)產(chǎn)生歧義。但是使用絕對(duì)路徑在表示文件時(shí),受到的限制很大,且不能在不同的操作系統(tǒng)下運(yùn)行,因?yàn)椴煌僮飨到y(tǒng)下絕對(duì)路徑的表達(dá)形式存在不同。
相對(duì)路徑是指書寫文件的部分路徑,例如\test\Hello.java,該路徑中只包含文件的部分路徑\test和文件的全名Hello.java,部分路徑是指當(dāng)前路徑下的子路徑,例如當(dāng)前程序在d:\abc下運(yùn)行,則該文件的完整路徑就是d:\abc\test。使用這種形式,可以更加通用的代表文件的位置,使得文件路徑產(chǎn)生一定的靈活性。
在Eclipse項(xiàng)目中運(yùn)行程序時(shí),當(dāng)前路徑是項(xiàng)目的根目錄,例如工作空間存儲(chǔ)在d:\javaproject,當(dāng)前項(xiàng)目名稱是Test,則當(dāng)前路徑是:d:\javaproject\Test。在控制臺(tái)下面運(yùn)行程序時(shí),當(dāng)前路徑是class文件所在的目錄,如果class文件包含包名,則以該class文件最頂層的包名作為當(dāng)前路徑。
這是java在多數(shù)操作系統(tǒng)中這樣操作,很顯然是要我們盡可能的使用相對(duì)路徑,但是在安卓中,其實(shí)多數(shù)情況下我們都是使用的絕對(duì)路徑。為什么呢?注意上面說到相對(duì)路徑是以當(dāng)前項(xiàng)目所在路徑為當(dāng)前路徑,但在安卓中我們是不可能在項(xiàng)目所在路徑目錄下做任何操作的,因?yàn)槠胀╦ava中我們的項(xiàng)目創(chuàng)建于服務(wù)器(pc也算是服務(wù)器),運(yùn)行于服務(wù)器,我們當(dāng)然能在服務(wù)器操作自己的文件目錄。但是安卓開發(fā)中,我們的項(xiàng)目一般是創(chuàng)建于自己工作的電腦,而運(yùn)行于手機(jī),既然apk已經(jīng)運(yùn)行于手機(jī)了,那項(xiàng)目就已經(jīng)部署到手機(jī)上了,應(yīng)該以apk在手機(jī)上的位置來確定相對(duì)路徑,但我們好像們沒有辦法操作這個(gè)路徑的,因?yàn)閍pk是在system目錄下,就算可以操作,在這個(gè)目錄下存取文件也是沒有意義的,比如我寫一個(gè)相冊(cè)程序,圖片肯定是放在外部存儲(chǔ)中,而如果我要保存一個(gè)應(yīng)用的一些設(shè)置數(shù)據(jù),我是放在內(nèi)部存儲(chǔ)的data目錄下,因此其實(shí)在安卓文件管理中,我們都是在操作絕對(duì)路徑。
File類
操作一個(gè)文件(讀寫,創(chuàng)建文件或者目錄)是通過File類來完成的,這個(gè)操作和java中完全一致。
Internal Storage內(nèi)部存儲(chǔ)空間
所謂的內(nèi)部存儲(chǔ)與外部存儲(chǔ),是指是否是手機(jī)內(nèi)置。手機(jī)內(nèi)置的存儲(chǔ)空間,稱為內(nèi)部存儲(chǔ),它是手機(jī)一旦出廠就無法改變,它也是手機(jī)的硬件指標(biāo)之一,通常來講手 機(jī)內(nèi)置存儲(chǔ)空間越大意味著手機(jī)價(jià)格會(huì)越貴(很多地方把它稱為手機(jī)內(nèi)存,但我們做軟件的知道,這并不準(zhǔn)確,內(nèi)存是指手機(jī)運(yùn)行時(shí)存儲(chǔ)程序,數(shù)據(jù)和指令的地方; 這里應(yīng)該是手機(jī)內(nèi)部存儲(chǔ)的簡(jiǎn)稱為內(nèi)存,而并非嚴(yán)格意義上的內(nèi)存)。
內(nèi)部存儲(chǔ)空間十分有限,因而顯得可貴,所以我們要盡可能避免使用;另外,它也是系統(tǒng)本身和系統(tǒng)應(yīng)用程序主要的數(shù)據(jù)存儲(chǔ)所在地,一旦內(nèi)部存儲(chǔ)空間耗盡,手機(jī) 也就無法使用了。所以對(duì)于內(nèi)部存儲(chǔ)空間,我們要盡量避免使用。上面所談到的Shared Preferences和下面要談到的SQLite數(shù)據(jù)庫(kù)也都是存儲(chǔ)在內(nèi)部存儲(chǔ)空間上的。
Android本身來講是一個(gè)Linux操作系統(tǒng),所以它的內(nèi)部存儲(chǔ)空間,對(duì)于應(yīng)用程序和用戶來講就是“/data/data"目錄。它與其他的(外部的 存儲(chǔ))相比有著比較穩(wěn)定,存儲(chǔ)方便,操作簡(jiǎn)單,更加安全(因?yàn)榭梢钥刂圃L問權(quán)限)等優(yōu)點(diǎn)。而它唯一的缺點(diǎn)就是它比較有限,比較可貴。
雖然,可以非常容易的知道程序本身的數(shù)據(jù)所在路徑,所有的應(yīng)用程序的數(shù)據(jù)路徑都是“/data/data/app-package-name/”,所有的 程序用到的數(shù)據(jù),比如libs庫(kù),SharedPreferences都是存放在這個(gè)路徑下面。但我們?cè)谑褂玫臅r(shí)候最好不要,或是千萬不要直接引用這個(gè)路 徑。
使用內(nèi)部存儲(chǔ)主要有二個(gè)方式,一個(gè)是文件操作,一個(gè)是文件夾操作。無論哪種方式,Context中都提供了相應(yīng)的函數(shù)來支持,使用Context不但操作 簡(jiǎn)單方便,最重要的是Context會(huì)幫助我們管理這些文件,也可以方便幫助我們控制文件的訪問權(quán)限。先來系統(tǒng)的說下Context中關(guān)于文件和文件夾操 作的函數(shù)有哪些。
a. 創(chuàng)建一個(gè)文件,并打開成一個(gè)文件輸出流,需要提供一個(gè)String,作為文件名
FileOutputStream output = Context.openOutputFile(filename, Context.MODE_PRIVATE); output.write(data);// use output to write whatever you like output.close();
b. 同樣,想打開一個(gè)文件作為輸入的話,也是只需要提供文件名
FileInputStream input = Context.openInputFile(filename); input.read(); input.close();
c. 列出所有的已創(chuàng)建的文件
String[] files = Context.fileList(); for (String file : files) { Log.e(TAG, "file is " + file); }
d. 刪除文件,能創(chuàng)建就要能夠刪除,當(dāng)然也會(huì)提供了刪除文件的接口,它也非常簡(jiǎn)單,只需要提供文件名
if (Context.deleteFile(filename)) { Log.e(TAG, "delete file " + filename + " sucessfully“); } else { Log.e(TAG, "failed to delete file " + filename); }
e. 獲取文件已創(chuàng)建文件的路徑,它返回一個(gè)文件對(duì)象用于操作路徑
File fileDir = Context.getFileDir(); Log.e(TAG, "fileDir " + fileDir.getAbsolutePath();
f. 創(chuàng)建一個(gè)目錄,需要傳入目錄名稱,它返回 一個(gè)文件對(duì)象用到操作路徑
File workDir = Context.getDir(dirName, Context.MODE_PRIVATE); Log.e(TAG, "workdir " + workDir.getAbsolutePath();
g. 以File對(duì)象方式查看所創(chuàng)建文件,需要傳入文件名,會(huì)返回文件對(duì)象
File store = Context.getFileStreamPath(filename); Log.e(TAG, "store " + store.length());
h. 獲取Cache路徑,無需要傳入?yún)?shù),返回文件對(duì)象
File cachedir = Context.getCacheDir(); Log.e(TAG, "cachedir " + cacheDir.getAbsolutePath());
總結(jié)一下文件相關(guān)操作,可以得出以下三個(gè)特點(diǎn):
1. 文件操作只需要向函數(shù)提供文件名,所以程序自己只需要維護(hù)文件名即可;
2. 不用自己去創(chuàng)建文件對(duì)象和輸入、輸出流,提供文件名就可以返回File對(duì)象或輸入輸出流
3. 對(duì)于路徑操作返回的都是文件對(duì)象。
如前所述,內(nèi)部存儲(chǔ)空間有限,可貴,安全,穩(wěn)定,所以應(yīng)該用來保存比較重要的數(shù)據(jù),比如用戶信息資料,口令秘碼等不需要與其他應(yīng)用程序共享的數(shù)據(jù)。也可以 用來創(chuàng)建臨時(shí)文件,但一定要注意及時(shí)刪除。另外,對(duì)于內(nèi)部存儲(chǔ)還有一個(gè)非常重要的特點(diǎn),那就是在應(yīng)用程序被卸載時(shí),應(yīng)用程序在內(nèi)部存儲(chǔ)空間的文件數(shù)據(jù)將全 部被刪除。系統(tǒng)這樣做的原因很簡(jiǎn)單,就是因?yàn)閮?nèi)部存儲(chǔ)很有限,它必須保證它的可用性,因?yàn)橐坏┨頋M,系統(tǒng)將無法再正常工作。
External Storage外部存儲(chǔ)空間
再來談?wù)勈謾C(jī)外部存儲(chǔ)空間,與內(nèi)部存儲(chǔ)空間相對(duì),外部存儲(chǔ) 空間是指手機(jī)出廠的時(shí)候不存在,用戶在使用時(shí)候可以自由添加的外部存儲(chǔ)介質(zhì)比如TS卡,SD卡等閃存儲(chǔ)介質(zhì)。這些閃存介質(zhì)由最初的空間小價(jià)格貴,到現(xiàn)在的 大容量?jī)r(jià)格便宜,所以幾乎每個(gè)支持外部存儲(chǔ)的手機(jī)上面都有大容量(大于等于2G)的閃存卡。
Android也是不例外,它完全支持外部存儲(chǔ)介質(zhì)。其實(shí)更確切的說,它是要依賴于外部存儲(chǔ)卡的,因?yàn)閷?duì)于Android系統(tǒng),如果沒有外部存儲(chǔ)卡,很多 的系統(tǒng)應(yīng)用無法使用,比如多媒體相關(guān)的應(yīng)用程序無法使用。雖然Android很依賴,但是外部存儲(chǔ)卡也有它自身的特點(diǎn),它最大的優(yōu)點(diǎn)就是存儲(chǔ)空間大,基本 上你可無限制的使用,也不怎么擔(dān)心去清除數(shù)據(jù)。就目前來看,很多程序都在使用外部存儲(chǔ)卡,但很少有程序去主動(dòng)清理數(shù)據(jù),所以無論你的SD卡有多大,它的可 用空間卻越來越少。與內(nèi)部存儲(chǔ)不同的是,當(dāng)程序卸載時(shí),它在外部存儲(chǔ)所創(chuàng)建的文件數(shù)據(jù)是不會(huì)被清除的。所以清理外部存儲(chǔ)空間的責(zé)任丟給了用戶自己,每隔一 段時(shí)間就去查看下SD卡,發(fā)現(xiàn)無用數(shù)據(jù)立馬刪除。外部存儲(chǔ)的缺點(diǎn)就是不是很穩(wěn)定,對(duì)于Android手機(jī)來講可以說,很不穩(wěn)定,本身閃存介質(zhì)就容易出問 題,SD卡處于不能正常使用的狀態(tài)十分多。
先來說說外部存儲(chǔ)相關(guān)的使用方法和API:
a Check media availability檢查介質(zhì)的可用性.
如前所述,外部存儲(chǔ)介質(zhì)的穩(wěn)定性十分的差,所以在使用之前一定要先檢查它的可用性,如果可用再去用
final String state = Environment.getExternalStorageState(); if (state.equals(Environment.MEDIA_MOUNTED) || state.equals(Environment.MEDIA_READ_ONLY)) {// sd card is ready to us
b. Get the directory獲取外部存儲(chǔ)卡的路徑
事實(shí)上,外部存儲(chǔ)卡的路徑是“/mnt/sdcard",所以你直接這樣寫去訪問也能訪問的到。鑒于可讀性和可移植性的考慮,建議這樣寫:
File sdcardDir = Environment.getExternalStorageDirectory();
c. For API 8 or greater, there are some other useful APIs helping to manager files and directories.
如果你使用API 8(Android 2.2)或者更高,那么SDK中又多了幾個(gè)操作外部存儲(chǔ)文件和路徑的接口,文檔中也建議開始者更加規(guī)范的使用SD卡。比如,創(chuàng)建相應(yīng)的目錄去存儲(chǔ)相應(yīng)的數(shù) 據(jù),Music,Picture,Video等。應(yīng)用程序目錄也變成了"/Android/data/package-name/data"。具體的使用 可以參考文檔,這里不重復(fù)。當(dāng)然,就像編程規(guī)范一樣,這里只是規(guī)范,你完全可以不遵守它,但出于可讀性和可移植性,還是建議按照文檔建議的去做。
下面總結(jié)一下使用時(shí)應(yīng)該注意的一些和外部存儲(chǔ)的特點(diǎn):
a. 外部存儲(chǔ)卡不是隨時(shí)想用就能夠用的,所以一定要記得在使用之前檢查它的可用性
b. 存儲(chǔ)在外部存儲(chǔ)卡上的數(shù)據(jù)是所有應(yīng)用程序都可見,用戶也可見(使用FileManager),所以安全性不是很好,雖然文檔聲稱可以在外部存儲(chǔ)卡上寫程序 私有數(shù)據(jù),但貌似沒用,用FileManager仍然可以刪除或編輯文件(Market上面的FileManager功能都十分的強(qiáng)大,能讓用戶看到SD 卡中的所有文件,和操作能看到的文件)。
c. Android手機(jī)支持把外部存儲(chǔ)卡Mount至PC做為U盤,當(dāng)連接數(shù)據(jù)線時(shí),這時(shí)SD卡變成了U盤連接到了另外的操作系統(tǒng)中。什么意思,就是在 Android當(dāng)中雖然有的文件屬性(隱藏,私有等),到了PC上就不一定管用了,用戶在PC上可以隨意操作文件(這就是第二點(diǎn)中所提及的)。
d. 如果使用外部存儲(chǔ)卡保存數(shù)據(jù),一定要額外做好異常處理:外部存儲(chǔ)卡不可用時(shí)把數(shù)據(jù)存入哪里;可用的時(shí)候再怎么同步數(shù)據(jù)(這是比較頭疼的地方,可行的做法就 是當(dāng)SD卡不可用時(shí)不準(zhǔn)用戶寫數(shù)據(jù),但這用戶體驗(yàn)又不是很好,但如你所知,很多應(yīng)用都這么干);你的數(shù)據(jù)被破壞了。當(dāng)然常見的異常也要考慮,比如空間滿 了,無法寫入,磁盤壞道等。
我們還可以看一下常見的文件目錄:
別忘了權(quán)限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> Log.i(TAG, "getFilesDir = " + getFilesDir()); Log.i(TAG, "getExternalFilesDir = " + getExternalFilesDir("exter_test").getAbsolutePath()); Log.i(TAG, "getDownloadCacheDirectory = " + Environment.getDownloadCacheDirectory().getAbsolutePath()); Log.i(TAG, "getDataDirectory = " + Environment.getDataDirectory().getAbsolutePath()); Log.i(TAG, "getExternalStorageDirectory = " + Environment.getExternalStorageDirectory().getAbsolutePath()); Log.i(TAG, "getExternalStoragePublicDirectory = " + Environment.getExternalStoragePublicDirectory("pub_test"));
以上內(nèi)容比較長(zhǎng),希望大家可以耐心閱讀,本文所述全部都是精華,關(guān)于Android文件存儲(chǔ)相關(guān)知識(shí),請(qǐng)點(diǎn)擊本站了解更多。
- 詳解Android數(shù)據(jù)存儲(chǔ)之Android 6.0運(yùn)行時(shí)權(quán)限下文件存儲(chǔ)的思考
- Android實(shí)現(xiàn)文件存儲(chǔ)并讀取的示例代碼
- android數(shù)據(jù)存儲(chǔ)之文件存儲(chǔ)方法
- android開發(fā)基礎(chǔ)教程—文件存儲(chǔ)功能實(shí)現(xiàn)
- Android圖片添加水印圖片并把圖片保存到文件存儲(chǔ)的實(shí)現(xiàn)代碼
- 實(shí)例詳解Android文件存儲(chǔ)數(shù)據(jù)方式
- 詳解Android開發(fā)數(shù)據(jù)持久化之文件存儲(chǔ)(附源碼)
- Android學(xué)習(xí)之文件存儲(chǔ)讀取
- Android編程之SharedPreferences文件存儲(chǔ)操作實(shí)例分析
- Android開發(fā)文件存儲(chǔ)實(shí)例
相關(guān)文章
Android 高版本API方法在低版本系統(tǒng)上的兼容性處理
本文主要介紹Android 高版本API方法在低版本系統(tǒng)上的兼容性處理的問題,這里提供了解決辦法,并附簡(jiǎn)單示例,來詳細(xì)說明解決問題步驟,有需要的小伙伴可以參考下2016-09-09Android開源AndroidSideMenu實(shí)現(xiàn)抽屜和側(cè)滑菜單
這篇文章主要為大家詳細(xì)介紹了Android開源AndroidSideMenu實(shí)現(xiàn)抽屜和側(cè)滑菜單,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-02-02Android 文件數(shù)據(jù)存儲(chǔ)實(shí)例詳解
這篇文章主要介紹了Android 文件數(shù)據(jù)存儲(chǔ)實(shí)例詳解的相關(guān)資料,這里附有實(shí)例代碼,幫助大家學(xué)習(xí)理解,需要的朋友可以參考下2016-12-12詳解Android輕量型數(shù)據(jù)庫(kù)SQLite
這篇文章主要為大家詳細(xì)介紹了Android輕量型數(shù)據(jù)庫(kù)SQLite,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-10-10Android實(shí)現(xiàn)好看的微信聊天氣泡效果
在聊天類應(yīng)用中,通常用氣泡作為聊天內(nèi)容的背景色,比如微信的聊天背景,別人發(fā)過來的是白色的氣泡,自己發(fā)的是綠色的氣泡。本文將用Android實(shí)現(xiàn)好看的微信聊天氣泡效果,感興趣的可以了解一下2022-06-06Android編程實(shí)現(xiàn)監(jiān)控apk安裝,卸載,替換的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)監(jiān)控apk安裝,卸載,替換的方法,涉及Android基于Intent監(jiān)控apk狀態(tài)的功能實(shí)現(xiàn)技巧,需要的朋友可以參考下2016-01-01Android 6.0調(diào)用相機(jī)圖冊(cè)崩潰的完美解決方案
這篇文章主要介紹了Android 6.0調(diào)用相機(jī)圖冊(cè)崩潰的完美解決方案,本文介紹的非常詳細(xì),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-09-09Android手勢(shì)密碼實(shí)現(xiàn)實(shí)例代碼
本篇文章主要介紹了Android手勢(shì)密碼實(shí)現(xiàn)實(shí)例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-04-04windows10安裝adb/fastboot驅(qū)動(dòng)超詳細(xì)圖文教程
這篇文章主要介紹了windows10安裝adb/fastboot超詳細(xì)圖文教程,安裝方法也很簡(jiǎn)單,只要adb安裝成功,fastboot就安裝好了,文中給大家介紹了問題分析及解決方法,需要的朋友可以參考下2023-01-01