Android 存儲使用參考

這個文章出自:https://www.liaohuqiu.net/cn/posts/storage-in-android/

怕被原作者刪了欢唾,直接復制過來

可能遇到的問題
Android 系統(tǒng)自身自帶有存儲,另外也可以通過 SD 卡來擴充存儲空間警没。 前者空間較小匈辱,后者空間大,但后者不一定可用杀迹。 開發(fā)應用亡脸,處理本地數據存取時,可能會遇到這些問題:
需要判斷 SD 卡是否可用: 占用過多機身內部存儲树酪,容易招致用戶反感浅碾,優(yōu)先將數據存放于 SD 卡;
應用數據存放路徑,同其他應用應該保持一致续语,應用卸載時垂谢,清除數據:
標新立異在 SD 卡根目錄建一個目錄,招致用戶反感
用戶卸載應用后疮茄,殘留目錄或者數據在用戶機器上滥朱,招致用戶反感

需要判斷兩者的可用空間: SD 卡存在時,可用空間反而小于機身內部存儲力试,這時應該選用機身存儲;

數據安全性徙邻,本應用數據不愿意被其他應用讀寫;

圖片緩存等,不應該被掃描加入到用戶相冊等媒體庫中去畸裳。

基本操作
使用外部存儲缰犁,需要的權限,在AndoridManifest.xml
中:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

從 API 19 / Andorid 4.4 / KITKAT 開始,不再需要顯式聲明這兩個權限帅容,除非要讀寫其他應用的應用數據($appDataDir
)

判斷 sd 卡可用:
/** * Check if the primary "external" storage device is available. * * @return */public static boolean hasSDCardMounted() { String state = Environment.getExternalStorageState(); if (state != null && state.equals(Environment.MEDIA_MOUNTED)) { return true; } else { return false; }}

存儲的用量情況
根據系統(tǒng)用戶不同颇象,所能占用的存儲空間大小也有不同
在 API level 9 及其以上時,File
對象的 getFreeSpace()
方法獲取系統(tǒng) root 用戶可用空間并徘;
getUsableSpace()
取非 root 用戶可用空間

當有多個存儲可用時獲取磁盤用量遣钳,根據當前系統(tǒng)情況選用合適的存儲。

根據系統(tǒng)存儲用量饮亏,合理設定 app 所用的空間大兴<帧;運行時路幸,也可做動態(tài)調整荐开。

在 API level 9 及其以上的系統(tǒng),可直接調用 File
對象的相關方法简肴,以下需自行計算:

@TargetApi(VERSION_CODES.GINGERBREAD)public static long getUsableSpace(File path) { if (path == null) { return -1; } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) { return path.getUsableSpace(); } else { if (!path.exists()) { return 0; } else { final StatFs stats = new StatFs(path.getPath()); return (long) stats.getBlockSize() * (long) stats.getAvailableBlocks(); } }}

路徑的規(guī)律
一般地晃听,通過 Context
和 Environment
相關的方法獲取文件存取的路徑。
通過這兩個類可獲取各種路徑砰识,如圖:
($rootDir)+- /data -> Environment.getDataDirectory()| || | ($appDataDir)| +- data/com.srain.cube.sample| || | ($filesDir)| +- files -> Context.getFilesDir() / Context.getFileStreamPath("")| | || | +- file1 -> Context.getFileStreamPath("file1")| | ($cacheDir)| +- cache -> Context.getCacheDir()| || +- app_$name ->(Context.getDir(String name, int mode)|| ($rootDir)+- /storage/sdcard0 -> Environment.getExternalStorageDirectory() | / Environment.getExternalStoragePublicDirectory("") | +- dir1 -> Environment.getExternalStoragePublicDirectory("dir1") | | ($appDataDir) +- Andorid/data/com.srain.cube.sample | | ($filesDir) +- files -> Context.getExternalFilesDir("") | | | +- file1 -> Context.getExternalFilesDir("file1") | +- Music -> Context.getExternalFilesDir(Environment.Music); | +- Picture -> ... Environment.Picture | +- ... | | ($cacheDir) +- cache -> Context.getExternalCacheDir() | +- ???

各個路徑的特性
下面介紹這些路徑的特性以及使用中需要注意的細節(jié):
根目錄($rootDir
):
內部存儲路徑: /data
, 通過 Environment.getDataDirectory()
獲取
外部存儲路徑: /storage/sdcard0
(也有類似 /mnt/ 這樣的)能扒,通過 Environment.getExternalStorageDirectory()
獲取
示例:
Environment.getDataDirectory(): /dataEnvironment.getExternalStorageDirectory(): /storage/sdcard0

應用數據目錄($appDataDir
)
內部儲存: $appDataDir = $rootDir/data/$packageName
,
外部存儲: $appDataDir = $rootDir/Andorid/data/$packageName

在這些目錄下的數據,在 app 卸載之后辫狼,會被系統(tǒng)刪除初斑,我們應將應用的數據放于這兩個目錄中。

外部存儲中膨处,公開的數據目錄见秤。 這些目錄將不會隨著應用的刪除而被系統(tǒng)刪除,請斟酌使用:

Environment.getExternalStorageDirectory(): /storage/sdcard0// 同 $rootDirEnvironment.getExternalStoragePublicDirectory(""): /storage/sdcard0Environment.getExternalStoragePublicDirectory("folder1"): /storage/sdcard0/folder1

應用數據目錄下的目錄
一般的在 $appDataDir 下真椿,會有兩個目錄
數據緩存:$cacheDir = $appDataDir/cache
:
內部存儲:Context.getCacheDir()
, 機身內存不足時鹃答,文件會被刪除
外部存儲:Context.getExternalCacheDir()

外部存儲沒有實時監(jiān)控,當空間不足時突硝,文件不會實時被刪除测摔,可能返回空對象
示例:
Context.getCacheDir(): /data/data/com.srain.cube.sample/cacheContext.getExternalCacheDir(): /storage/sdcard0/Android/data/com.srain.cube.sample/cache

文件目錄 $filesDir = $appDataDir/files
:
內部存儲:通過 Context.getFilesDir()
獲取
Context.getFileStreamPath(String name)
返回以name
為文件名的文件對象,name
為空解恰,則返回 $filesDir
本身
示例:
Context.getFilesDir(): /data/data/com.srain.cube.sample/filesContext.getFileStreamPath(""): /data/data/com.srain.cube.sample/filesContext.getFileStreamPath("file1"): /data/data/com.srain.cube.sample/files/file1

外部存儲:通過 Context.getExternalFilesDir(String type)
, type
為空字符串時獲取.
type
系統(tǒng)指定了幾種類型:
Environment.DIRECTORY_MUSICEnvironment.DIRECTORY_PICTURES...

示例:
Context.getExternalFilesDir(""): /storage/sdcard0/Android/data/com.srain.cube.sample/filesContext.getExternalFilesDir(Environment.DIRECTORY_MUSIC) /storage/sdcard0/Android/data/com.srain.cube.sample/files/Music

$cacheDir / $filesDir
安全性
在內部存儲中锋八,$cacheDir
, $filesDir
是 app 安全的,其他應用無法讀取本應用的數據护盈,而外部存儲則不是查库。
在外部存儲中,這兩個文件夾其他應用程序也可訪問黄琼。
在外部存儲中,$filesDir
中的媒體文件,不會被當做媒體掃描出來脏款,加到媒體庫中围苫。

$cacheDir / $filesDir
同級目錄
在內部存儲中:通過 Context.getDir(String name, int mode)
可獲取和 $filesDir
/ $cacheDir
同級的目錄
目錄的命名規(guī)則為 app_ + name
, 通過 mode 可控制此目錄為 app 私有還是其他 app 可讀寫。
示例:
Context.getDir("dir1", MODE_PRIVATE): Context.getDir: /data/data/com.srain.cube.sample/app_dir1

特別注意, 對于外部存儲撤师,獲取 $cacheDir
或者 $filesDir
及其下的路徑

在 API level 8 以下剂府,或者空間不足,相關的方法獲路徑為空時剃盾,需要自己構造腺占。
@TargetApi(VERSION_CODES.FROYO)public static File getExternalCacheDir(Context context) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO)) { File path = context.getExternalCacheDir(); // In some case, even the sd card is mounted, // getExternalCacheDir will return null // may be it is nearly full. if (path != null) { return path; } } // Before Froyo or the path is null, // we need to construct the external cache folder ourselves final String cacheDir = "/Android/data/" + context.getPackageName() + "/cache/"; return new File(Environment.getExternalStorageDirectory().getPath() + cacheDir);}

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市痒谴,隨后出現的幾起案子衰伯,更是在濱河造成了極大的恐慌,老刑警劉巖积蔚,帶你破解...
    沈念sama閱讀 211,348評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件意鲸,死亡現場離奇詭異,居然都是意外死亡尽爆,警方通過查閱死者的電腦和手機怎顾,發(fā)現死者居然都...
    沈念sama閱讀 90,122評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來漱贱,“玉大人槐雾,你說我怎么就攤上這事》ǎ” “怎么了募强?”我有些...
    開封第一講書人閱讀 156,936評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長彪笼。 經常有香客問我钻注,道長,這世上最難降的妖魔是什么配猫? 我笑而不...
    開封第一講書人閱讀 56,427評論 1 283
  • 正文 為了忘掉前任幅恋,我火速辦了婚禮,結果婚禮上泵肄,老公的妹妹穿的比我還像新娘捆交。我一直安慰自己,他們只是感情好腐巢,可當我...
    茶點故事閱讀 65,467評論 6 385
  • 文/花漫 我一把揭開白布品追。 她就那樣靜靜地躺著,像睡著了一般冯丙。 火紅的嫁衣襯著肌膚如雪肉瓦。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,785評論 1 290
  • 那天,我揣著相機與錄音泞莉,去河邊找鬼哪雕。 笑死,一個胖子當著我的面吹牛鲫趁,可吹牛的內容都是我干的斯嚎。 我是一名探鬼主播,決...
    沈念sama閱讀 38,931評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼挨厚,長吁一口氣:“原來是場噩夢啊……” “哼堡僻!你這毒婦竟也來了?” 一聲冷哼從身側響起疫剃,我...
    開封第一講書人閱讀 37,696評論 0 266
  • 序言:老撾萬榮一對情侶失蹤钉疫,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后慌申,有當地人在樹林里發(fā)現了一具尸體陌选,經...
    沈念sama閱讀 44,141評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,483評論 2 327
  • 正文 我和宋清朗相戀三年蹄溉,在試婚紗的時候發(fā)現自己被綠了咨油。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,625評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡柒爵,死狀恐怖役电,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情棉胀,我是刑警寧澤法瑟,帶...
    沈念sama閱讀 34,291評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站唁奢,受9級特大地震影響霎挟,放射性物質發(fā)生泄漏。R本人自食惡果不足惜麻掸,卻給世界環(huán)境...
    茶點故事閱讀 39,892評論 3 312
  • 文/蒙蒙 一酥夭、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧脊奋,春花似錦熬北、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至久又,卻和暖如春巫延,著一層夾襖步出監(jiān)牢的瞬間效五,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工烈评, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留火俄,地道東北人。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓讲冠,卻偏偏與公主長得像,于是被迫代替她去往敵國和親适瓦。 傳聞我的和親對象是個殘疾皇子竿开,可洞房花燭夜當晚...
    茶點故事閱讀 43,492評論 2 348

推薦閱讀更多精彩內容