轉(zhuǎn)載:http://www.reibang.com/p/ebca517ae7d5
http://blog.csdn.net/u012702547/article/details/50269639
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2013/0923/1557.html
該文章只是用于個(gè)人學(xué)習(xí)記錄,里面有些部分是直接轉(zhuǎn)載別人的,所以寫的比較亂,建議大家還是從原作者的博客去學(xué)習(xí)荒澡,同時(shí)尊重原作者的著作權(quán)溜宽,所轉(zhuǎn)載內(nèi)容的鏈接在上面趣效。
簡(jiǎn)單介紹:
內(nèi)部存儲(chǔ)空間中的應(yīng)用私有目錄
對(duì)于設(shè)備中每一個(gè)安裝的 App,系統(tǒng)都會(huì)在內(nèi)部存儲(chǔ)空間的 data/data 目錄下以應(yīng)用包名為名字自動(dòng)創(chuàng)建與之對(duì)應(yīng)的文件夾疮蹦。這個(gè)文件夾用于 App 中的 WebView 緩存頁(yè)面信息惰瓜,SharedPreferences 和 SQLiteDatabase 持久化應(yīng)用相關(guān)數(shù)據(jù)等否副。
對(duì)于沒有 Root 過的手機(jī),普通用戶是無(wú)法查看 data/data 目錄內(nèi)容的崎坊。不過開發(fā)人員可以使用模擬器調(diào)試應(yīng)用备禀,并通過 DDMS(Dalvik Debug Monitor Server)提供的 File Explorer 工具查看模擬器設(shè)備的存儲(chǔ)空間。
操作路徑:
第一步:Android Studio --> Tools --> Android --> Android Device Monitor奈揍;
第二步:Window --> Show View --> Android --> File Explorer曲尸。
Android SDK 提供有如下方法可以獲取并操作內(nèi)部存儲(chǔ)空間下應(yīng)用私有目錄文件的方,都位于 Application Context 中男翰,供開發(fā)者直接調(diào)用:
getFilesDir():
getCacheDir():
deleteFile()
fileList()
等等另患,也可以通過 Environment 類訪問:
Environment.getDataDirectory();
注意:當(dāng)用戶卸載 App 時(shí),系統(tǒng)自動(dòng)刪除 data/data 目錄下對(duì)應(yīng)包名的文件夾及其內(nèi)容蛾绎。
外部存儲(chǔ)空間中的應(yīng)用私有目錄
考慮內(nèi)部存儲(chǔ)空間容量有限昆箕,普通用戶不能直接直觀地查看目錄文件等其他原因,Android 在外部存儲(chǔ)空間中也提供有特殊目錄供應(yīng)用存放私有文件租冠,文件路徑為:
/storage/emulated/0/Android/data/app package name
備注:一般設(shè)備都有內(nèi)置 SD 卡鹏倘,同時(shí)也提供外部 SD 卡拓展,可能對(duì)應(yīng)路徑的目錄名有所差異肺稀。
值得注意的是第股,與內(nèi)部存儲(chǔ)空間的應(yīng)用私有目錄不同的是:
第一,默認(rèn)情況下话原,系統(tǒng)并不會(huì)自動(dòng)創(chuàng)建外部存儲(chǔ)空間的應(yīng)用私有目錄夕吻。只有在應(yīng)用需要的時(shí)候,開發(fā)人員通過 SDK 提供的 API 創(chuàng)建該目錄文件夾和操作文件夾內(nèi)容繁仁。
第二涉馅,自 Android 7.0 開始,系統(tǒng)對(duì)應(yīng)用私有目錄的訪問權(quán)限進(jìn)一步限制黄虱。其他 App 無(wú)法通過 file:// 這種形式的 Uri 直接讀寫該目錄下的文件內(nèi)容稚矿,而是通過 FileProvider 訪問。
第三捻浦,宿主 App 可以直接讀寫內(nèi)部存儲(chǔ)空間中的應(yīng)用私有目錄晤揣;而在 4.4 版本開始,宿主 App 才可以直接讀寫外部存儲(chǔ)空間中的應(yīng)用私有目錄朱灿,使開發(fā)人員無(wú)需在 Manifest 文件中或者動(dòng)態(tài)申請(qǐng)外部存儲(chǔ)空間的文件讀寫權(quán)限昧识。
而相同點(diǎn)在于:同屬于應(yīng)用私有目錄,當(dāng)用戶卸載 App 時(shí)盗扒,系統(tǒng)也會(huì)自動(dòng)刪除外部存儲(chǔ)空間下的對(duì)應(yīng) App 私有目錄文件夾及其內(nèi)容跪楞。
同樣缀去,Android SDK 中也提供有便捷的 API 供開發(fā)人員直接操作外部存儲(chǔ)空間下的應(yīng)用私有目錄:
getExternalFilesDir()
getExternalCacheDir()
等等,當(dāng)然甸祭,也可以通過 Environment 類間接操作缕碎,只不過需要向用戶申請(qǐng)操作權(quán)限:
Environment.getExternalStorageDirectory();
類似于 File 和 Cache 默認(rèn)分類目錄,開發(fā)人員也可以在應(yīng)用私有目錄中創(chuàng)建屬于自己的自定義目錄池户,方便于分類存儲(chǔ)應(yīng)用相關(guān)文件咏雌。
值得注意的一點(diǎn)是,對(duì)于外部存儲(chǔ)空間下的應(yīng)用私有目錄文件煞檩,由于普通用戶可以自由修改和刪除处嫌,開發(fā)人員在使用時(shí),一定要做好判空處理和異常捕獲斟湃,防止應(yīng)用崩潰退出熏迹!
外部存儲(chǔ)空間中的公共目錄
通常來(lái)說(shuō),應(yīng)用涉及到的持久化數(shù)據(jù)分為兩類:應(yīng)用相關(guān)數(shù)據(jù)和應(yīng)用無(wú)關(guān)數(shù)據(jù)凝赛。前者是指專供宿主 App 使用的數(shù)據(jù)信息注暗,比如一些應(yīng)用的配置信息,數(shù)據(jù)庫(kù)信息墓猎,緩存文件等捆昏。當(dāng)應(yīng)用被卸載,這些信息也應(yīng)該被隨之刪除毙沾,避免存儲(chǔ)空間產(chǎn)生不必要的占用骗卜。
相對(duì)而言,后者更偏向于這類信息:當(dāng)應(yīng)用被卸載左胞,用戶仍然希望保留于設(shè)備當(dāng)中的信息寇仓。常見如,拍照類應(yīng)用的圖片文件烤宙,用戶是使用瀏覽器手動(dòng)下載的文件等遍烦。
顯然,無(wú)論是內(nèi)部存儲(chǔ)空間躺枕,還是外部?jī)?chǔ)存空間服猪,上述兩個(gè)應(yīng)用私有目錄由于其特有的生命周期(隨著應(yīng)用卸載而自動(dòng)清除)只適合存儲(chǔ)應(yīng)用相關(guān)數(shù)據(jù)。
或者從訪問權(quán)限上來(lái)說(shuō)拐云,應(yīng)用無(wú)關(guān)數(shù)據(jù)應(yīng)該是宿主應(yīng)用希望與其他應(yīng)用共享這些數(shù)據(jù)的罢猪,應(yīng)該存放在外部存儲(chǔ)空間的公共目錄文件夾下。
外部存儲(chǔ)空間已經(jīng)為用戶默認(rèn)分類出一些公共目錄叉瘩。開發(fā)人員可以通過 Environment 類提供的方法直接獲取相應(yīng)目錄的絕對(duì)路徑膳帕,傳遞不同的 type 參數(shù)類型即可:
Environment.getExternalStoragePublicDirectory(String type);
Envinonment 類提供諸多 type 參數(shù)的常量,比如:
DIRECTORY_MUSIC:Music
DIRECTORY_MOVIES:Movies
DIRECTORY_PICTURES:Pictures
DIRECTORY_DOWNLOADS:Download
等等房揭,以第一個(gè)常量為例备闲,音樂類別的公共目錄絕對(duì)路徑為:/storage/emulated/0/Music。如果你使用文件管理器打開設(shè)備的外部存儲(chǔ)空間的話捅暴,均可以看到這些公共目錄文件夾恬砂。
面對(duì)如此諸多的默認(rèn)類別,開發(fā)人員在保存自己應(yīng)用的公共文件時(shí)蓬痒,也要養(yǎng)成良好的習(xí)慣泻骤,將要保存的數(shù)據(jù)分門別類地保存在不同公共目錄下。當(dāng)然梧奢,你也可以在公共目錄下再次創(chuàng)建屬于自己應(yīng)用的目錄狱掂,便于管理。
** 注意:訪問外部存儲(chǔ)空間時(shí)記得申請(qǐng)讀寫權(quán)限亲轨! **
** 外部存儲(chǔ)空間中的其他目錄 **
一般來(lái)說(shuō)趋惨,利用兩種應(yīng)用私有目錄和公共目錄便能夠存儲(chǔ)應(yīng)用中需要保存的數(shù)據(jù)和文件。如果這些還不夠的話惦蚊,那一定是你的開發(fā)姿勢(shì)不對(duì)器虾。在 Code Review 的前提下,如果還是不夠的話蹦锋,還可以在外部存儲(chǔ)空間自由創(chuàng)建其他目錄兆沙,通過這個(gè)方式獲取外部存儲(chǔ)空間的絕對(duì)路徑,然后操作文件:
Environment.getExternalStorageDirectory();
小結(jié)
使用應(yīng)用私有目錄保存應(yīng)用相關(guān)數(shù)據(jù)莉掂,使用公共目錄保存應(yīng)用無(wú)關(guān)數(shù)據(jù)(共享數(shù)據(jù))葛圃。無(wú)論哪種情況,都需要做好數(shù)據(jù)分類保存憎妙,便于清除等統(tǒng)一管理库正。隨便打開手機(jī)上的幾個(gè)應(yīng)用,不難發(fā)現(xiàn)尚氛,很多應(yīng)用都包含一個(gè)清理緩存的功能诀诊。事實(shí)上,開發(fā)人員清理的就是應(yīng)用相關(guān)數(shù)據(jù)阅嘶,也就是應(yīng)用私有目錄下的文件属瓣。
考慮到外部存儲(chǔ)空間上的內(nèi)容可能被用戶手動(dòng)刪除,或者卸載拓展 SD 卡等不可控因素讯柔,操作前記得使用 Environment 類提供的 API 方法判斷容量是否充足抡蛙、文件是否存在等情況,做好異常捕獲魂迄,減少應(yīng)用崩潰率粗截。相信這一定是一個(gè)良好的習(xí)慣。
詳細(xì)介紹:
內(nèi)存捣炬,我們?cè)谟⑽闹蟹Q作memory熊昌,內(nèi)部存儲(chǔ)绽榛,我們稱為InternalStorage,外部存儲(chǔ)我們稱為ExternalStorage婿屹。注意內(nèi)部存儲(chǔ)不是內(nèi)存灭美。從用戶角度來(lái)說(shuō)SD卡有內(nèi)置和外置之分,但是對(duì)于開發(fā)者昂利,只有內(nèi)部存儲(chǔ)和外部存儲(chǔ)届腐,內(nèi)置SD卡和外置SD卡都屬于外部存儲(chǔ)范疇。
打開DDMS
這里有三個(gè)文件夾需要我們重視蜂奸,一個(gè)是data犁苏,一個(gè)是mnt,一個(gè)是storage扩所,我們下面就詳細(xì)說(shuō)說(shuō)這三個(gè)文件夾围详。
1.內(nèi)部存儲(chǔ)
data文件夾就是我們常說(shuō)的內(nèi)部存儲(chǔ),當(dāng)我們打開data文件夾之后(沒有root的手機(jī)不能打開該文件夾)祖屏,里邊有兩個(gè)文件夾值得我們關(guān)注短曾,如下:
一個(gè)文件夾是app文件夾,還有一個(gè)文件夾就是data文件夾赐劣,app文件夾里存放著我們所有安裝的app的apk文件嫉拐,其實(shí),當(dāng)我們調(diào)試一個(gè)app的時(shí)候魁兼,可以看到控制臺(tái)輸出的內(nèi)容婉徘,有一項(xiàng)是uploading .....就是上傳我們的apk到這個(gè)文件夾,上傳成功之后才開始安裝咐汞。另一個(gè)重要的文件夾就是data文件夾了盖呼,這個(gè)文件夾里邊都是一些包名,打開這些包名之后我們會(huì)看到這樣的一些文件:
1.data/data/包名/shared_prefs2.data/data/包名/databases3.data/data/包名/files
4.data/data/包名/cache
如果打開過data文件化撕,應(yīng)該都知道這些文件夾是干什么用的几晤,我們?cè)谑褂胹haredPreferenced的時(shí)候,將數(shù)據(jù)持久化存儲(chǔ)于本地植阴,其實(shí)就是存在這個(gè)文件中的xml文件里蟹瘾,我們App里邊的數(shù)據(jù)庫(kù)文件就存儲(chǔ)于databases文件夾中,還有我們的普通數(shù)據(jù)存儲(chǔ)在files中掠手,緩存文件存儲(chǔ)在cache文件夾中憾朴,存儲(chǔ)在這里的文件我們都稱之為內(nèi)部存儲(chǔ)。
3.外部存儲(chǔ)
外部存儲(chǔ)才是我們平時(shí)操作最多的喷鸽,外部存儲(chǔ)一般就是我們上面看到的storage文件夾众雷,當(dāng)然也有可能是mnt文件夾,這個(gè)不同廠家有可能不一樣。
一般來(lái)說(shuō)砾省,在storage文件夾中有一個(gè)sdcard文件夾鸡岗,這個(gè)文件夾中的文件又分為兩類,一類是公有目錄编兄,還有一類是私有目錄纤房,其中的公有目錄有九大類,比如DCIM翻诉、DOWNLOAD等這種系統(tǒng)為我們創(chuàng)建的文件夾,私有目錄就是Android這個(gè)文件夾捌刮,這個(gè)文件夾打開之后里邊有一個(gè)data文件夾碰煌,打開這個(gè)data文件夾,里邊有許多包名組成的文件夾绅作。
外部存儲(chǔ)中的文件是可以被用戶或者其他應(yīng)用程序修改的芦圾,有兩種類型的文件(或者目錄):
1.公共文件Public files:文件是可以被自由訪問,且文件的數(shù)據(jù)對(duì)其他應(yīng)用或者用戶來(lái)說(shuō)都是由意義的俄认,當(dāng)應(yīng)用被卸載之后个少,其卸載前創(chuàng)建的文件仍然保留。比如camera應(yīng)用眯杏,生成的照片大家都能訪問夜焦,而且camera不在了,照片仍然在岂贩。
2.私有文件Private files:其實(shí)由于是外部存儲(chǔ)的原因即是是這種類型的文件也能被其他程序訪問茫经,只不過一個(gè)應(yīng)用私有的文件對(duì)其他應(yīng)用其實(shí)是沒有訪問價(jià)值的(惡意程序除外)。外部存儲(chǔ)上萎津,應(yīng)用私有文件的價(jià)值在于卸載之后卸伞,這些文件也會(huì)被刪除。類似于內(nèi)部存儲(chǔ)锉屈。因?yàn)檫@些文件也會(huì)在應(yīng)用刪除的時(shí)候跟隨這一起刪掉~只是和內(nèi)部?jī)?chǔ)存不同的是這個(gè)部分可以給用戶和其他應(yīng)用訪問荤傲。所以才叫外部?jī)?chǔ)存的私有部分嘛。
所有應(yīng)用程序的外部存儲(chǔ)的私有文件都放在根目錄的Android/data/下颈渊,目錄形式為/Android/data/<package_name>/
3.操作存儲(chǔ)空間
首先遂黍,經(jīng)過上面的分析,大家已經(jīng)明白了俊嗽,什么是內(nèi)部存儲(chǔ)妓湘,什么是外部存儲(chǔ),以及這兩種存儲(chǔ)方式分別存儲(chǔ)在什么位置乌询,一般來(lái)說(shuō)榜贴,我們不會(huì)自己去操作內(nèi)部存儲(chǔ)空間,沒有root權(quán)限的話,我們也沒法操作內(nèi)部存儲(chǔ)空間唬党,事實(shí)上內(nèi)部存儲(chǔ)主要是由系統(tǒng)來(lái)維護(hù)的鹃共。不過在代碼中我們是可以訪問到這個(gè)文件夾的。由于內(nèi)部存儲(chǔ)空間有限驶拱,在開發(fā)中我們一般都是操作外部存儲(chǔ)空間霜浴,Google官方建議我們App的數(shù)據(jù)應(yīng)該存儲(chǔ)在外部存儲(chǔ)的私有目錄中該App的包名下,這樣當(dāng)用戶卸載掉App之后蓝纲,相關(guān)的數(shù)據(jù)會(huì)一并刪除阴孟,如果你直接在/storage/sdcard目錄下創(chuàng)建了一個(gè)應(yīng)用的文件夾,那么當(dāng)你刪除應(yīng)用的時(shí)候税迷,這個(gè)文件夾就不會(huì)被刪除永丝。
經(jīng)過以上的介紹,我們可以總結(jié)出下面一個(gè)表格:
如果按照路徑的特征箭养,我們又可以將文件存儲(chǔ)的路徑分為兩大類慕嚷,一類是路徑中含有包名的,一類是路徑中不含有包名的毕泌,含有包名的路徑喝检,因?yàn)楹湍硞€(gè)App有關(guān),所以對(duì)這些文件夾的訪問都是調(diào)用Context里邊的方法撼泛,而不含有包名的路徑挠说,和某一個(gè)App無(wú)關(guān),我們可以通過Environment中的方法來(lái)訪問愿题。如下圖:
說(shuō)到這里纺涤,我想大家對(duì)內(nèi)部存儲(chǔ)、外部存儲(chǔ)該有了一個(gè)清晰的認(rèn)識(shí)了吧抠忘。我們?cè)陂_發(fā)中撩炊,不建議往內(nèi)部存儲(chǔ)中寫太多的數(shù)據(jù),畢竟空間有限崎脉。外部存儲(chǔ)在使用的時(shí)候最好能夠?qū)⑽募娣旁谒接心夸浵屡】龋@樣有利于系統(tǒng)維護(hù),也避免用戶的反感囚灼。
操作權(quán)限:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
內(nèi)部存儲(chǔ)操作:
private void createPrivateFile()//向內(nèi)部存儲(chǔ)寫文件
{
String filename = "myfile.txt";
String string = "Hello world!";
FileOutputStream outputStream;
try {
outputStream = openFileOutput(filename, Context.MODE_PRIVATE);
outputStream.write(string.getBytes());
outputStream.close();
Toast.makeText(MainActivity.this,"文件位置 在"+getFilesDir().getAbsolutePath(),Toast.LENGTH_LONG).show();
} catch (Exception e)
{
e.printStackTrace();
Toast.makeText(MainActivity.this,"出錯(cuò)誤了哦",Toast.LENGTH_SHORT).show();
}
}
//列出所有的已創(chuàng)建的文件,這個(gè)可能不容易想到骆膝,Context居然有這樣的方法。
String[] files = Context.fileList();
for(String file : files) {
Log.e(TAG, "file is "+ file);
}
//刪除文件灶体,能創(chuàng)建就要能夠刪除阅签,當(dāng)然也會(huì)提供了刪除文件的接口,它也非常簡(jiǎn)單蝎抽,只需要提供文件名
f(Context.deleteFile(filename)) {
Log.e(TAG, "delete file "+ filename + " sucessfully“);
} else {
Log.e(TAG, "failed to deletefile " + filename);
}
外部存儲(chǔ)操作
由于外部存儲(chǔ)可能不可用—比如政钟,當(dāng)用戶已將存儲(chǔ)裝載到電腦或已移除提供外部存儲(chǔ)的 SD 卡時(shí)—因此,在訪問它之前,您應(yīng)始終確認(rèn)其容量养交。 您可以通過調(diào)用 getExternalStorageState() 查詢外部存儲(chǔ)狀態(tài)精算。 如果返回的狀態(tài)為 MEDIA_MOUNTED,那么您可以對(duì)您的文件進(jìn)行讀寫碎连。 例如灰羽,以下方法對(duì)于確定存儲(chǔ)可用性非常有用:
/* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
return true;
}
return false;
}
/* Checks if external storage is available to at least read */
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)供其他應(yīng)用和用戶自由使用的文件。 當(dāng)用戶卸載您的應(yīng)用時(shí)鱼辙,用戶應(yīng)仍可以使用這些文件廉嚼。
例如,您的應(yīng)用拍攝的照片或其他已下載的文件倒戏。
私有文件
屬于您的應(yīng)用且在用戶卸載您的應(yīng)用時(shí)應(yīng)予刪除的文件怠噪。 盡管這些文件在技術(shù)上可被用戶和其他應(yīng)用訪問(因?yàn)樗鼈兇鎯?chǔ)在外部存儲(chǔ)中), 但它們實(shí)際上不向您的應(yīng)用之外的用戶提供任何輸出值峭梳。 當(dāng)用戶卸載您的應(yīng)用時(shí),系統(tǒng)會(huì)刪除應(yīng)用外部私有目錄中的所有文件蹂喻。
例如葱椭,您的應(yīng)用下載的其他資源或臨時(shí)介質(zhì)文件。
如果您要將公共文件保存在外部存儲(chǔ)設(shè)備上口四,請(qǐng)使用 getExternalStoragePublicDirectory() 方法獲取表示外部存儲(chǔ)設(shè)備上相應(yīng)目錄的 File孵运。 該方法使用指定您想要保存以便它們可以與其他公共文件在邏輯上組織在一起的文件類型的參數(shù),比如 DIRECTORY_MUSIC 或 DIRECTORY_PICTURES蔓彩。例如:
public File getAlbumStorageDir(String albumName) {
// Get the directory for the user's public pictures directory.
File file = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), albumName);
if (!file.mkdirs()) {
Log.e(LOG_TAG, "Directory not created");
}
return file;
}
如果您要保存您的應(yīng)用專用文件治笨,您可以通過調(diào)用 getExternalFilesDir()并向其傳遞指示您想要的目錄類型的名稱,從而獲取相應(yīng)的目錄赤嚼。通過這種方法創(chuàng)建的各個(gè)目錄將添加至封裝您的應(yīng)用的所有外部存儲(chǔ)文件的父目錄旷赖,當(dāng)用戶卸載您的應(yīng)用時(shí),系統(tǒng)會(huì)刪除這些文件更卒。
public File getAlbumStorageDir(Context context, String albumName) {
// Get the directory for the app's private pictures directory.
File file = new File(context.getExternalFilesDir(
Environment.DIRECTORY_PICTURES), albumName);
if (!file.mkdirs()) {
Log.e(LOG_TAG, "Directory not created");
}
return file;
}
如果沒有適合您文件的預(yù)定義子目錄名稱等孵,您可以改為調(diào)用 getExternalFilesDir() 并傳遞 null。這將返回外部存儲(chǔ)上您的應(yīng)用的專用目錄的根目錄蹂空。