十年網(wǎng)站開(kāi)發(fā)經(jīng)驗(yàn) + 多家企業(yè)客戶(hù) + 靠譜的建站團(tuán)隊(duì)
量身定制 + 運(yùn)營(yíng)維護(hù)+專(zhuān)業(yè)推廣+無(wú)憂(yōu)售后,網(wǎng)站問(wèn)題一站解決
Android 使用 VFS (Virtual File System) 虛擬文件系統(tǒng)。VFS提供了供存儲(chǔ)設(shè)備掛載的節(jié)點(diǎn),同一存儲(chǔ)設(shè)備經(jīng)過(guò)分區(qū)后,不同的分區(qū)可以?huà)燧d到不同的節(jié)點(diǎn)上,如手機(jī)的內(nèi)置存儲(chǔ)卡。
創(chuàng)新互聯(lián)建站專(zhuān)業(yè)為企業(yè)提供遂昌網(wǎng)站建設(shè)、遂昌做網(wǎng)站、遂昌網(wǎng)站設(shè)計(jì)、遂昌網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁(yè)設(shè)計(jì)與制作、遂昌企業(yè)網(wǎng)站模板建站服務(wù),十余年遂昌做網(wǎng)站經(jīng)驗(yàn),不只是建網(wǎng)站,更提供有價(jià)值的思路和整體網(wǎng)絡(luò)服務(wù)。
內(nèi)置存儲(chǔ)卡 / 外置SD卡
內(nèi)部存儲(chǔ) / 外部存儲(chǔ)
VFS 的目錄以 / 為根節(jié)點(diǎn),根節(jié)點(diǎn)下面又有不同的節(jié)點(diǎn)。物理存儲(chǔ)設(shè)備就是掛載到這些節(jié)點(diǎn)上。
內(nèi)部存儲(chǔ)卡/外置SD卡 ≠ 內(nèi)部存儲(chǔ)/外部存儲(chǔ)
首先明確, 內(nèi)置存儲(chǔ)卡/外置SD卡 是在 物理層面 相對(duì)于 手機(jī)大眾用戶(hù) 來(lái)說(shuō)的。
外置SD卡:可手動(dòng)插拔的SD卡。
內(nèi)置存儲(chǔ)卡:焊接在手機(jī)內(nèi)部不可拆卸的存儲(chǔ)卡。
而, 內(nèi)部存 /外部存儲(chǔ) 是在 文件系統(tǒng)邏輯層面 相對(duì)于 開(kāi)發(fā)者 來(lái)說(shuō)的,指具體的路徑。
一般針對(duì)某個(gè)應(yīng)用而言的,屬于該應(yīng)用的存儲(chǔ)路徑叫內(nèi)部存儲(chǔ),反之為外部存儲(chǔ)。
路徑: /data/data/package_name
/data/data/ 下都是已安裝應(yīng)用的目錄,該目錄下包含的文件都是以包名作為文件名的目錄,例如 /data/data/com.sankuai.meituan
獲取內(nèi)部存儲(chǔ)的方式如下:
其中,參數(shù) mode 指創(chuàng)建模式,一種 4 種
注意: Android 7.0 以上 android.os.Build.VERSION.SDK_INT=Build.VERSION_CODES.N 使用3/4 常量時(shí),將會(huì)導(dǎo)致SecurityException,這意味著 不能通過(guò)名稱(chēng)共享私有文件 。
嘗試共享 URI將會(huì)導(dǎo)致FileUriExposedException,StrictMode API政策禁止在您的應(yīng)用外部公開(kāi)。如果您的應(yīng)用需要與其他應(yīng)用共享私有文件,則可以使用 FileProvider 與 FLAG_GRANT_READ_URI_PERMISSION 配合使用。 Android 7.0 行為變更 通過(guò)FileProvider在應(yīng)用間共享文件吧
外部存儲(chǔ),可以是 外置SD卡 或 內(nèi)置存儲(chǔ)卡的部分分區(qū)。
外部存儲(chǔ),分為 公共目錄 和 私有目錄
獲取方式
檢查可用性的方法:
Android 4.3 以下,只能通過(guò) Context#getExternalFilesDir(type) 來(lái)獲取外部存儲(chǔ)在內(nèi)置存儲(chǔ)卡分區(qū)的私有目錄,無(wú)法獲取外置SD卡。
Android 4.3 開(kāi)始,可以通過(guò) Context#getExternalFilesDirs(type) 獲取一個(gè)File數(shù)組,包含了內(nèi)置存儲(chǔ)卡分區(qū)和外置SD的私有目錄地址。
可以使用兼容庫(kù)的靜態(tài)方法 ContextCompate.getExternalFilesDirs() 兼容 4.3。
感謝以下文章作者
解析Android內(nèi)部存儲(chǔ)、外部存儲(chǔ)的區(qū)別
??在平常使用Android手機(jī)的時(shí)候,我們都知道,幾乎每一個(gè)app都在/data/data/相應(yīng)的包名的文件夾下保存數(shù)據(jù)。那這些數(shù)據(jù)怎么進(jìn)行保存的呢?在這里,將簡(jiǎn)單的介紹一下。
??Context類(lèi)中有一個(gè)openFileOutPut方法,這個(gè)方法可以將我們的數(shù)據(jù)保存在data目錄下的文件里面。
??openFileOutput(String name, int mode)方法中帶兩個(gè)參數(shù),第一個(gè)參數(shù)是文件名,這里只能寫(xiě)文件的名字,不能包含路徑,因?yàn)樗械臄?shù)據(jù)都保存在/data/data/應(yīng)用包名/files/目錄下;第二個(gè)參數(shù)是文件的操作模式,有MDOE_PRIVATE,MODE_APPEND,MODE_WORLD_READABLE和MODE_WORLD_WRITEABLE。
??其中MODE_PRIVATE模式的是默認(rèn)的操作模式,每一次寫(xiě)入的內(nèi)容時(shí),都會(huì)覆蓋前面的內(nèi)容;MODE_APPEND模式表示的是每次寫(xiě)入的內(nèi)容追加在前面的后面;MODE_WORLD_READABLE表示的是其他應(yīng)用程序可以對(duì)該文件進(jìn)行寫(xiě)的操作;MODE_WORLD_WRITEABLE表示的是其他應(yīng)用程序可以對(duì)該文件進(jìn)行讀的操作。不過(guò)在后面的兩種模式過(guò)于危險(xiǎn),google已經(jīng)在Android 4.2中廢棄了。
??openFileOutput()方法返回的是一個(gè)FileOutPutStream的對(duì)象,得到了這個(gè)對(duì)象,就可以使用Java的IO流來(lái)對(duì)文件的使用了。
??點(diǎn)擊保存過(guò)后,就會(huì)把我們的數(shù)據(jù)保存在data目錄下。
??如果我們想要查看的話(huà),就可以在Android studio(我是2.3.2的版本)中找到Tools-Android-Android Device Monitor
??再打開(kāi)/data/data/應(yīng)用包名/files/,發(fā)現(xiàn)有一個(gè)文件,就是我們之前創(chuàng)建的一個(gè)文件。
??我們可以點(diǎn)擊右上角的圖標(biāo)進(jìn)行相應(yīng)的導(dǎo)出工作,對(duì)相應(yīng)的文件進(jìn)行導(dǎo)出操作。
??在Context類(lèi)中,與openFileOutput方法對(duì)應(yīng)的是openFileInput方法,用戶(hù)從data目錄讀取相應(yīng)的數(shù)據(jù)。這個(gè)方法相較于openFileOutput方法簡(jiǎn)單一些。
效果示意圖:
安卓開(kāi)發(fā)離不開(kāi)手機(jī)存儲(chǔ),然而大部分人對(duì)于安卓開(kāi)發(fā)中的存儲(chǔ)概念存在誤區(qū),內(nèi)部外部SD卡傻傻分不清?
以下引用來(lái)自對(duì) 官方文檔 的理解
呵呵呵,先別說(shuō)話(huà),然而重點(diǎn)來(lái)了(敲黑板),按照官方的說(shuō)法,
內(nèi)部存儲(chǔ)是指系統(tǒng)的存儲(chǔ)空間,沒(méi)有root是訪(fǎng)問(wèn)不到的呦親,比如sharedPreferenced或者database都是保存在這里面的。
外部存儲(chǔ),又分為 2 部分:
然而現(xiàn)實(shí)中,常常有同事把手機(jī)那個(gè)32G,64G存儲(chǔ)叫做內(nèi)部存儲(chǔ)= =,寶寶好累,人家明明是 ExternalStorage ?。?/p>
希望本篇能讓大家對(duì)內(nèi)外部存儲(chǔ)有一個(gè)正確鮮明的認(rèn)識(shí)
getFilesDir()
路徑如下
文檔 云:若想操作該路徑,你需要一個(gè)輸出流:
就像這樣:
注: this 是 context 對(duì)象
在
路徑下會(huì)看到新文件哦
如果你還想讀取的話(huà), 文檔 云:你需要一個(gè)輸入流:
Log如下
getCacheDir()
文檔 云:
路徑如下:
特別的,還有g(shù)etDir() :
getDir("- -!.txt", Context.MODE_PRIVATE).getAbsolutePath()
路徑如下:
app_是系統(tǒng)自己加上去的
內(nèi)部存儲(chǔ)就是系統(tǒng)的存儲(chǔ),沒(méi)有root你是看不到的,內(nèi)部存儲(chǔ)最大特點(diǎn)就是可以用Context對(duì)象調(diào)用各個(gè)獲取路徑的方法。比如: context.fileList()
那就是
下的文件遍歷。
而 deleteFile("ABC") 就是
刪除下名為 ABC 的文件
/br/br/br
操作外部存儲(chǔ)你首先需要以下權(quán)限
當(dāng)你申請(qǐng)了write權(quán)限,那么read權(quán)限默認(rèn)也就通過(guò)啦
再判斷狀態(tài):
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState))
Environment.getExternalStorageDirectory()
這個(gè)路徑根據(jù)手機(jī)廠家不同會(huì)有些許變化
直接傳入 Environment 中的常量獲取相應(yīng)的路徑,如下:
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_ALARMS));
或者
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES));
公有目錄下,系統(tǒng)會(huì)區(qū)分不同類(lèi)別 (例如鈴聲在系統(tǒng)設(shè)置中顯示為鈴聲而不是音樂(lè))
4.4以后訪(fǎng)問(wèn)該目錄不再需要權(quán)限了
getExternalFilesDir(String type)
eg.
getExternalFilesDir(Environment.DIRECTORY_MUSIC)
特別的:ContextCompat下的
ContextCompat.getExternalFilesDirs(context,type)
返回一個(gè)File[],在4.4以后第一條數(shù)據(jù)默認(rèn)外部主存儲(chǔ)目錄,第二條數(shù)據(jù)就是sd卡路徑啦,但是注意4.4之前是沒(méi)有第二條數(shù)據(jù)的哦
該目錄下的特點(diǎn)是卸載程序后,該目錄和其下所有文件均會(huì)被刪除
getExternalCacheDir()
注意,使用該目錄注意管理空間,你不能等系統(tǒng)幫你清理,而是自己清理不再需要的緩存
特別的:ContextCompat下的
ContextCompat.getExternalCacheDirs()
道理同上
發(fā)現(xiàn)特點(diǎn)了嗎朋友,無(wú)論外部?jī)?nèi)部,只有路徑中有包名,那么就是私有的,而且是隨著程序的卸載而被刪除的, 有包名的路徑均是Context中的方法,而公有的路徑均是Environment調(diào)用的
這個(gè)貨真真是要了老命,一般的方法根部不好使,結(jié)合網(wǎng)上有的方法加上公司項(xiàng)目中的方法,總結(jié)如下:
百分百好用的獲取SD卡路徑方法:
最后集合 path 中的值就是SD卡根目錄
雖然無(wú)視版本百分百好用,但是如果你的手機(jī)有SD卡槽卻沒(méi)插SD卡,該方法最后 path 返回的是 null ,也就是說(shuō)該方法無(wú)法判斷到底是沒(méi)插SD卡還是根本不支持SD卡
其實(shí)還有一種方法
String path = System.getenv("SECONDARY_STORAGE");
該方法只要你手機(jī)支持SD卡,無(wú)論你插沒(méi)插SD卡,均會(huì)返回SD卡路徑,但是 6.0及以上該方法被移除
Environment中源碼其實(shí)就是根據(jù)這個(gè)方法獲取路徑的
安卓官方文檔大家一定要看,他就是我們開(kāi)發(fā)者的權(quán)威呀,圣經(jīng)呀??!
安卓設(shè)備的物理存儲(chǔ) 分為兩大塊,內(nèi)部存儲(chǔ)和外部存儲(chǔ)
存儲(chǔ)分區(qū),是android系統(tǒng)對(duì)APP訪(fǎng)問(wèn)外部存儲(chǔ) 添加了限制;開(kāi)啟存儲(chǔ)分區(qū)后 APP只能訪(fǎng)問(wèn)自己目錄下的文件和公共文件,
需要特別指出的是android 10 雖支持存儲(chǔ)分區(qū) 但可不開(kāi)啟,對(duì)于android11 來(lái)說(shuō),必須開(kāi)啟存儲(chǔ)分區(qū),android11必須使用存儲(chǔ)分區(qū),
即使設(shè)置 android:requestLegacyExternalStorage="true" 也無(wú)效
對(duì)原來(lái)的內(nèi)部存儲(chǔ)沒(méi)有什么影響,但是對(duì)外部存儲(chǔ)有影響;
外部 存儲(chǔ)有兩個(gè)區(qū)域 app私有區(qū)域和app共享區(qū)域;
例如:在android 10以下的手機(jī)設(shè)備上 調(diào)起相機(jī)拍照,使用 Uri.fromFile 的方式來(lái)創(chuàng)建照片文件是 沒(méi)有問(wèn)題的,但是 android11上,即使調(diào)起了相機(jī)拍照后 也無(wú)法成功保存照片
android 7 后支持 應(yīng)用之間共享文件,這就是FileProvider的作用;
使用FileProvider 需要在清單文件中 聲明,注意一下 android:authorities指定的屬性值,盡可能的保證唯一性 一般以".fileProvider" 結(jié)尾
其中 file_paths文件在 Resource/xml 下,原來(lái)指定共享的 文件路徑;
然后使用FileProvider API 來(lái)生成File的Uri路徑;
這個(gè)"com.xx.fileprovider" 就是 授權(quán)認(rèn)證的信息,如果填寫(xiě)的和清單文件中的不一致 會(huì) 導(dǎo)致文件讀寫(xiě)時(shí) 錯(cuò)誤;
在使用File存儲(chǔ)App數(shù)據(jù)時(shí),我們需要了解Android系統(tǒng)的存儲(chǔ)系統(tǒng)。Android的存儲(chǔ)分為內(nèi)部存儲(chǔ)和外部存儲(chǔ)。
由于Android系統(tǒng)的廠商比較多,對(duì)于外部存儲(chǔ)目錄的定義有所不同,可能在根目錄下的mnt,sdcard和storage下。以storage為例,打開(kāi)emulated/0目錄,外部存儲(chǔ)目錄就出現(xiàn)了。雖然可以通過(guò)多種路徑打開(kāi)外部存儲(chǔ)文件,但是最終他們的路徑是相同的:
mnt:
storage:
sdcard:
外部存儲(chǔ)目錄下包含兩大類(lèi):公有目錄和私有目錄
私有目錄:
對(duì)比下來(lái)External有以下幾點(diǎn)優(yōu)點(diǎn):
缺點(diǎn):
內(nèi)部存儲(chǔ)與外部存儲(chǔ)權(quán)限申請(qǐng)對(duì)比如下:
首先我們要獲取外部存儲(chǔ)目標(biāo)文件的路徑:
然后確定自己需要?jiǎng)?chuàng)建的文件名,結(jié)合上面的到的路徑,創(chuàng)建一個(gè)File對(duì)象:
Android系統(tǒng)默認(rèn)數(shù)據(jù)清理的路徑是,內(nèi)部存儲(chǔ)目錄中相應(yīng)的cache文件夾中的文件和外部存儲(chǔ)中相應(yīng)的cache文件夾中的文件。
你的app的internal storage 目錄是以你的app的包名作為標(biāo)識(shí)存放在Android文件系統(tǒng)的特定目錄下[data/data/com.example.xx]。 從技術(shù)上講,如果你設(shè)置文件為可讀的,那么其他app就可以讀取你的internal文件。然而,其他app需要知道你的包名與文件名。若是你沒(méi)有設(shè)置為可讀或者可寫(xiě),其他app是沒(méi)有辦法讀寫(xiě)的。因此只要你使用MODE_PRIVATE ,那么這些文件就不可能被其他app所訪(fǎng)問(wèn)。
另外記住一點(diǎn),內(nèi)部存儲(chǔ)在你的APP卸載的時(shí)候,會(huì)一塊被刪除,因此,我們可以在cache目錄里面放置我們的圖片緩存,而且cache與files的差別在于,如果手機(jī)的內(nèi)部存儲(chǔ)空間不夠了,會(huì)自行選擇cache目錄進(jìn)行刪除,因此,不要把重要的文件放在cache文件里面,可以放置在files里面,因?yàn)檫@個(gè)文件只有在APP被卸載的時(shí)候才會(huì)被刪除。還有要注意的一點(diǎn)是,如果應(yīng)用程序是更新操作,內(nèi)部存儲(chǔ)不會(huì)被刪除,區(qū)別于被用戶(hù)手動(dòng)卸載。
不管你是使用 getExternalStoragePublicDirectory() 來(lái)存儲(chǔ)可以共享的文件,還是使用 getExternalFilesDir() 來(lái)儲(chǔ)存那些對(duì)于你的app來(lái)說(shuō)是私有的文件,有一點(diǎn)很重要,那就是你要使用那些類(lèi)似DIRECTORY_PICTURES 的API的常量。那些目錄類(lèi)型參數(shù)可以確保那些文件被系統(tǒng)正確的對(duì)待。例如,那些以DIRECTORY_RINGTONES 類(lèi)型保存的文件就會(huì)被系統(tǒng)的media scanner認(rèn)為是ringtone而不是音樂(lè)。
在開(kāi)發(fā)中,不建議往內(nèi)部存儲(chǔ)中寫(xiě)太多的數(shù)據(jù),畢竟空間有限。外部存儲(chǔ)在使用的時(shí)候最好能夠?qū)⑽募娣旁谒接心夸浵?,這樣有利于系統(tǒng)維護(hù),也避免用戶(hù)的反感。
徹底理解android中的內(nèi)部存儲(chǔ)與外部存儲(chǔ)
Android存儲(chǔ)挖坑記
緩存文件可以放在哪里?它們各自的特點(diǎn)是什么