關(guān)于android中的內(nèi)部存儲與外部存儲

作者:劉朋

鏈接:https://www.zhihu.com/question/19866689/answer/131250089

來源:知乎

著作權(quán)歸作者所有或颊,轉(zhuǎn)載請聯(lián)系作者獲得授權(quán)。

選擇內(nèi)部或外部存儲

所有 Android 設(shè)備都有兩個文件存儲區(qū)域:“內(nèi)部”和“外部”存儲。這些名稱在 Android 早期產(chǎn)生夭苗,當(dāng)時大多數(shù)設(shè)備都提供內(nèi)置的非易失性內(nèi)存(內(nèi)部存儲),以及移動存儲介質(zhì)慕匠,比如微型 SD 卡(外部存儲)杭朱。一些設(shè)備將永久性存儲空間劃分為“內(nèi)部”和“外部”分區(qū)阅仔,即便沒有移動存儲介質(zhì),也始終有兩個存儲空間弧械,并且無論外部存儲設(shè)備是否可移動八酒,API 的行為均一致。以下列表匯總了關(guān)于各個存儲空間的實際信息刃唐。

內(nèi)部存儲:

它始終可用羞迷。

只有您的應(yīng)用可以訪問此處保存的文件。

當(dāng)用戶卸載您的應(yīng)用時画饥,系統(tǒng)會從內(nèi)部存儲中移除您的應(yīng)用的所有文件衔瓮。

當(dāng)您希望確保用戶或其他應(yīng)用均無法訪問您的文件時,內(nèi)部存儲是最佳選擇抖甘。

外部存儲:

它并非始終可用热鞍,因為用戶可采用 USB 存儲設(shè)備的形式裝載外部存儲,并在某些情況下會從設(shè)備中將其移除衔彻。

它是全局可讀的薇宠,因此此處保存的文件可能不受您控制地被讀取。

當(dāng)用戶卸載您的應(yīng)用時艰额,只有在您通過 getExternalFilesDir() 將您的應(yīng)用的文件保存在目錄中時澄港,系統(tǒng)才會從此處移除您的應(yīng)用的文件。

對于無需訪問限制以及您希望與其他應(yīng)用共享或允許用戶使用計算機訪問的文件柄沮,外部存儲是最佳位置回梧。

注:

在 Android N 之前,內(nèi)部文件可以通過放寬文件系統(tǒng)權(quán)限讓其他應(yīng)用訪問祖搓。而如今不再是這種情況狱意。如果您希望讓其他應(yīng)用訪問私有文件的內(nèi)容,則您的應(yīng)用可使用 FileProvider棕硫。

提示:

盡管應(yīng)用默認(rèn)安裝在內(nèi)部存儲中髓涯,但您可在您的清單文件中指定 android:installLocation 屬性,這樣您的應(yīng)用便可安裝在在外部存儲中哈扮。當(dāng) APK 非常大且它們的外部存儲空間大于內(nèi)部存儲時纬纪,用戶更青睞這個選擇。 如需了解詳細(xì)信息滑肉,請參閱應(yīng)用安裝位置包各。

獲取外部存儲的權(quán)限

要向外部存儲寫入信息,您必須在您的清單文件中請求 WRITE_EXTERNAL_STORAGE 權(quán)限靶庙。

注意:

目前问畅,所有應(yīng)用都可以讀取外部存儲,而無需特別的權(quán)限。 但這在將來版本中會進(jìn)行更改护姆。如果您的應(yīng)用需要讀取外部存儲(但不向其寫入信息)矾端,那么您將需要聲明 READ_EXTERNAL_STORAGE 權(quán)限。要確保您的應(yīng)用繼續(xù)正常工作卵皂,您應(yīng)在更改生效前聲明此權(quán)限秩铆。

將文件保存在內(nèi)部存儲中

在內(nèi)部存儲中保存文件時,您可以通過調(diào)用以下兩種方法之一獲取作為 File 的相應(yīng)目錄:

1.getFilesDir()

返回表示您的應(yīng)用的內(nèi)部目錄的 File 灯变。

2.getCacheDir()

返回表示您的應(yīng)用臨時緩存文件的內(nèi)部目錄的 File殴玛。 務(wù)必刪除所有不再需要的文件并對在指定時間您使用的內(nèi)存量實現(xiàn)合理大小限制,比如添祸,1MB滚粟。 如果在系統(tǒng)即將耗盡存儲,它會在不進(jìn)行警告的情況下刪除您的緩存文件刃泌。

要在這些目錄之一中新建文件

1.您可以使用 File() 構(gòu)造函數(shù)凡壤,傳遞指定您的內(nèi)部存儲目錄的上述方法之一所提供的 File。例如:

File file = new File(context.getFilesDir(), filename);

2.或者蔬咬,您可以調(diào)用 openFileOutput() 獲取寫入到內(nèi)部目錄中的文件的 FileOutputStream鲤遥。例如,下面顯示如何向文件寫入一些文本:

String filename = "myfile";

String string = "Hello world!";

FileOutputStream outputStream;

try {

outputStream = openFileOutput(filename, Context.MODE_PRIVATE);

outputStream.write(string.getBytes());

outputStream.close();

} catch (Exception e) {

e.printStackTrace();

}

3.或者林艘,如果您需要緩存某些文件盖奈,您應(yīng)改用 createTempFile()。例如狐援,以下方法從 URL 提取文件名并正在您的應(yīng)用的內(nèi)部緩存目錄中以該名稱創(chuàng)建文件:

public File getTempFile(Context context, String url) {

File file;

try {

String fileName = Uri.parse(url).getLastPathSegment();

file = File.createTempFile(fileName, null, context.getCacheDir());

} catch (IOException e) {

// Error while creating file

}

return file;

}

注:您的應(yīng)用的內(nèi)部存儲設(shè)備目錄由您的應(yīng)用在 Android 文件系統(tǒng)特定位置中的軟件包名稱指定钢坦。從技術(shù)上講,如果您將文件模式設(shè)置為可讀啥酱,那么爹凹,另一應(yīng)用也可以讀取您的內(nèi)部文件。 但是镶殷,此應(yīng)用也需要知道您的應(yīng)用的軟件包名稱和文件名禾酱。 其他應(yīng)用無法瀏覽您的內(nèi)部目錄并且沒有讀寫權(quán)限,除非您明確將文件設(shè)置為可讀或可寫绘趋。 只要您為內(nèi)部存儲上的文件使用 MODE_PRIVATE颤陶,其他應(yīng)用便從不會訪問它們。

將文件保存在外部存儲中

由于外部存儲可能不可用—比如陷遮,當(dāng)用戶已將存儲裝載到電腦或已移除提供外部存儲的 SD 卡時—因此滓走,在訪問它之前,您應(yīng)始終確認(rèn)其容量帽馋。 您可以通過調(diào)用 getExternalStorageState() 查詢外部存儲狀態(tài)搅方。 如果返回的狀態(tài)為 MEDIA_MOUNTED比吭,那么您可以對您的文件進(jìn)行讀寫。 例如姨涡,以下方法對于確定存儲可用性非常有用:

/

* 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)用進(jìn)行修改衩藤,但您可在此處保存兩類文件:公共文件

應(yīng)供其他應(yīng)用和用戶自由使用的文件。 當(dāng)用戶卸載您的應(yīng)用時绣溜,用戶應(yīng)仍可以使用這些文件慷彤。

例如娄蔼,您的應(yīng)用拍攝的照片或其他已下載的文件怖喻。

私有文件

屬于您的應(yīng)用且在用戶卸載您的應(yīng)用時應(yīng)予刪除的文件。 盡管這些文件在技術(shù)上可被用戶和其他應(yīng)用訪問(因為它們存儲在外部存儲中)岁诉, 但它們實際上不向您的應(yīng)用之外的用戶提供任何輸出值锚沸。 當(dāng)用戶卸載您的應(yīng)用時,系統(tǒng)會刪除應(yīng)用外部私有目錄中的所有文件涕癣。

例如哗蜈,您的應(yīng)用下載的其他資源或臨時介質(zhì)文件。

如果您要將公共文件保存在外部存儲設(shè)備上坠韩,請使用 getExternalStoragePublicDirectory() 方法獲取表示外部存儲設(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)建的各個目錄將添加至封裝您的應(yīng)用的所有外部存儲文件的父目錄洞翩,當(dāng)用戶卸載您的應(yīng)用時磕谅,系統(tǒng)會刪除這些文件繁扎。

例如际插,您可以使用以下方法來創(chuàng)建個人相冊的目錄:

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助币。這將返回外部存儲上您的應(yīng)用的專用目錄的根目錄朦蕴。

切記疏尿,getExternalFilesDir() 在用戶卸載您的應(yīng)用時刪除的目錄內(nèi)創(chuàng)建目錄榆鼠。如果您正保存的文件應(yīng)在用戶卸載您的應(yīng)用后仍然可用—比如震鹉,當(dāng)您的應(yīng)用是照相機并且用戶要保留照片時—您應(yīng)改用 getExternalStoragePublicDirectory()俱笛。

無論您對于共享的文件使用 {@linkandroid.os.Environment#getExternalStoragePublicDirectory getExternalStoragePublicDirectory()} 還是對您的應(yīng)用專用文件使用 getExternalFilesDir(),您使用諸如 DIRECTORY_PICTURES 的 API 常數(shù)提供的目錄名稱非常重要足陨。這些目錄名稱可確保系統(tǒng)正確處理文件嫂粟。 例如,保存在 DIRECTORY_RINGTONES 中的文件由系統(tǒng)媒體掃描程序歸類為鈴聲墨缘,而不是音樂星虹。

查詢可用空間

如果您事先知道您將保存的數(shù)據(jù)量零抬,您可以查出是否有足夠的可用空間,而無需調(diào)用 getFreeSpace() 或 getTotalSpace() 引起 IOException宽涌。這些方法分別提供目前的可用空間和存儲卷中的總空間平夜。 此信息也可用來避免填充存儲卷以致超出特定閾值。

但是卸亮,系統(tǒng)并不保證您可以寫入與 getFreeSpace() 指示的一樣多的字節(jié)忽妒。如果返回的數(shù)字比您要保存的數(shù)據(jù)大小大出幾 MB,或如果文件系統(tǒng)所占空間不到 90%兼贸,則可安全繼續(xù)操作段直。否則,您可能不應(yīng)寫入存儲溶诞。

注:保存您的文件之前鸯檬,您無需檢查可用空間量。 您可以嘗試立刻寫入文件螺垢,然后在 IOException 出現(xiàn)時將其捕獲喧务。 如果您不知道所需的確切空間量,您可能需要這樣做枉圃。 例如功茴,如果在保存文件之前通過將 PNG 圖像轉(zhuǎn)換成 JPEG 更改了文件的編碼,您事先將不知道文件的大小孽亲。

刪除文件

您應(yīng)始終刪除不再需要的文件坎穿。刪除文件最直接的方法是讓打開的文件參考自行調(diào)用 delete()。

myFile.delete();

如果文件保存在內(nèi)部存儲中墨林,您還可以請求 Context 通過調(diào)用 deleteFile() 來定位和刪除文件:

myContext.deleteFile(fileName);

注:當(dāng)用戶卸載您的應(yīng)用時赁酝,Android 系統(tǒng)會刪除以下各項:

您保存在內(nèi)部存儲中的所有文件

您使用 getExternalFilesDir() 保存在外部存儲中的所有文件。

但是旭等,您應(yīng)手動刪除使用 getCacheDir() 定期創(chuàng)建的所有緩存文件并且定期刪除不再需要的其他文件酌呆。】

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末搔耕,一起剝皮案震驚了整個濱河市隙袁,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌弃榨,老刑警劉巖菩收,帶你破解...
    沈念sama閱讀 206,013評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異鲸睛,居然都是意外死亡娜饵,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評論 2 382
  • 文/潘曉璐 我一進(jìn)店門官辈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來箱舞,“玉大人遍坟,你說我怎么就攤上這事∏绻桑” “怎么了愿伴?”我有些...
    開封第一講書人閱讀 152,370評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長电湘。 經(jīng)常有香客問我隔节,道長,這世上最難降的妖魔是什么寂呛? 我笑而不...
    開封第一講書人閱讀 55,168評論 1 278
  • 正文 為了忘掉前任怎诫,我火速辦了婚禮,結(jié)果婚禮上昧谊,老公的妹妹穿的比我還像新娘刽虹。我一直安慰自己,他們只是感情好呢诬,可當(dāng)我...
    茶點故事閱讀 64,153評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著胖缤,像睡著了一般尚镰。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上哪廓,一...
    開封第一講書人閱讀 48,954評論 1 283
  • 那天狗唉,我揣著相機與錄音,去河邊找鬼涡真。 笑死分俯,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的哆料。 我是一名探鬼主播缸剪,決...
    沈念sama閱讀 38,271評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼东亦!你這毒婦竟也來了杏节?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,916評論 0 259
  • 序言:老撾萬榮一對情侶失蹤典阵,失蹤者是張志新(化名)和其女友劉穎奋渔,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體壮啊,經(jīng)...
    沈念sama閱讀 43,382評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡嫉鲸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,877評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了歹啼。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片玄渗。...
    茶點故事閱讀 37,989評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡减江,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出捻爷,到底是詐尸還是另有隱情辈灼,我是刑警寧澤,帶...
    沈念sama閱讀 33,624評論 4 322
  • 正文 年R本政府宣布也榄,位于F島的核電站巡莹,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏甜紫。R本人自食惡果不足惜降宅,卻給世界環(huán)境...
    茶點故事閱讀 39,209評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望囚霸。 院中可真熱鬧腰根,春花似錦、人聲如沸拓型。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,199評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽劣挫。三九已至册养,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間压固,已是汗流浹背球拦。 一陣腳步聲響...
    開封第一講書人閱讀 31,418評論 1 260
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留帐我,地道東北人坎炼。 一個月前我還...
    沈念sama閱讀 45,401評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像拦键,于是被迫代替她去往敵國和親谣光。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,700評論 2 345

推薦閱讀更多精彩內(nèi)容