標籤:activity android開發 資料 應用 緩衝
前言:上一篇文章寫了在Android中利用SharedPreferences儲存資料,SharedPreferences在儲存資料的時候主要是儲存一些應用程式的設定資訊或者少量的使用者資訊,並且是以key-value形式儲存的String類的資訊,比較有局限性。比如你需要儲存從網路擷取的圖片到本地作為快取資料,並且數量比較大,SharedPreferences就不能滿足你的需求了,這個時候就要用到基本上所有平台都會用到的檔案儲存。
Android中以檔案形式把資料儲存到磁碟上與其他平台基本上都是類似的,本篇文章將會介紹如何利用java.io.Files的API函數進行檔案的讀寫操作。
選擇內部儲存還是外部儲存:
所有的Android裝置有兩個檔案儲存體地區:“內部”和“外部”儲存。這些名字來自Android的早期,那時大多數裝置提供了內建的非易失性儲存空間(記憶體),加上一個可移動的儲存介質如micro SD卡(外部儲存)。現在的Android裝置基本上內建的儲存空間都很大,比如16g或者32g,這裡的16g和32g是指的總共磁碟大小,相當於你新買的電腦一塊嶄新的硬碟。在手機出廠的時候會在這塊磁碟上燒上android系統,android系統會把整個磁碟進行分區,一部分提供給android系統存放系統檔案使用,類似windows的系統硬碟,但是要比windows上許可權嚴格的多,使用者是不能隨意訪問這部分檔案的(root除外),這一部分叫做內部儲存,剩餘的部分使用者可以自由使用,手機連上電腦時查看到的也只是這部分檔案,叫做外部儲存,相當於windows上的其他磁碟(比如D盤),當然有的使用者又添加了一張micro-SD卡,這部分也算做外部儲存,相當於windows上的外接硬碟吧。
內部儲存和外部儲存是有區別的,在利用的時候需要注意他們各自的特點:
內部儲存:
- 始終存在可用;
- 儲存的檔案預設只能被儲存檔案的app訪問,各個應用之間不可以彼此訪問,只能訪問自己儲存的檔案。
- 當應用被卸載的時候應用儲存的檔案會被完全清除掉;
- 如果你想要儲存的檔案很安全,不會被使用者和其他應用讀取到,那麼你可以選擇內部儲存這種方式。
外部儲存:
- 不一定存在,比如有的手機出廠是只有內部儲存,沒有外部儲存,使用者自己又沒有安裝micro-SD卡,這時外部儲存是停用;
- 讀寫完全開放的,所以你儲存的資料可能會被使用者和可其它程式讀取;
- 卸載應用時只會刪除通過getExternalFilesDir()擷取到的目錄檔案;
- 如果你的檔案沒有必要控制存取權限,可以允許其它應用或者使用者查看,那麼外部儲存是不錯的選擇;
註:在預設情況下應用程式安裝到內部儲存,您可以指定android:installLocation屬性在AndroidManifest.xml檔案中,這樣你的應用程式可以安裝在外部儲存空間。對於使用者來說有這個安裝選項非常實用,當一些應用程式非常大,內部儲存空間不足的時候使用者可以把應用安裝到外部儲存空間。
擷取外部儲存許可權:要想在外部儲存上隱藏檔首先要擷取外部儲存讀寫權限,許可權的聲明都是在AndroidManifest.xml檔案中,代碼如下:
<manifest ...> <uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"/> ...</manifest>
注意:現在所有的應用程式預設都有外部儲存的讀取許可權,你不需要在AndroidManifest.xml檔案中進行聲明,但是這種預設的許可權可能會在以後的Android版本中變更,所以最好還是要在AndroidManifest中顯式的進行讀取許可權聲明,免得在以後的版本中程式出現問題,讀取許可權聲明如下:
<manifest ...> <uses-permissionandroid:name="android.permission.READ_EXTERNAL_STORAGE"/> ...</manifest>
另外:1、寫入許可權隱含就有讀取許可權;2、內部儲存不需要進行許可權聲明,應用程式對於內部儲存預設就有讀寫檔案的許可權;
儲存到內部儲存:檔案儲存體需要建立檔案,當把檔案儲存到內部儲存時你可以擷取內部隱藏檔通過下面的兩個方法:
1、File getFilesDir ();
返回一個檔案目錄,這個目錄下儲存應用程式的資料,通過 openFileOutput(String, int) 建立的檔案都儲存在這個檔案目錄下。這個目錄大概是:data/data/包名/files,比如豌豆莢應用程式是:data/data/com.wandoujia.phoenix2/files/
2、File getCacheDir ();
返回一個檔案目錄,這個目錄存放的是應用程式快取檔案,當系統空間不足時這部分檔案首先會被刪除。這個目錄大概是:data/data/包名/cache,比如豌豆莢應用程式是:data/data/com.wandoujia.phoenix2/cache/ 注意:快取檔案的刪除不應該依賴系統去刪除它,最好的辦法是給你的應用緩衝設定一個最大值,比如1M,當達到這個值時你應該去刪除部分快取檔案以便能再次利用這部分空間。
當你想要在內部儲存寫入一個檔案時,首先要建立一個檔案,可以通過File的構造器,傳入上面兩個方法擷取的路徑作為參數,很方便的就能建立一個檔案,例如:
File file = newFile(context.getFilesDir(), filename);
然後再通過上面的file建立檔案流,寫入檔案,當然你可能更喜歡下面的方式,通過調用 openFileOutput() 建立一個FileOutputStream ,然後寫入檔案,代碼如下:
String filename ="myfile";Stringstring="Hello world!";FileOutputStream outputStream;try{ outputStream = openFileOutput(filename,Context.MODE_PRIVATE); outputStream.write(string.getBytes()); outputStream.close();}catch(Exception e){ e.printStackTrace();}
當你需要建立一個快取檔案時,你可以通過下面的方式:
File file = newFile(context.getCacheDir(), filename);
或者,你會更喜歡下面的方式,通過File的creatTempFile方法在cache目錄建立臨時檔案,檔案的尾碼是.tmp:
publicFile 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;}
注意:通常情況下你的應用程式內部隱藏檔是不會被其他應用程式訪問到的,因為其他程式的訪問首先需要知道你應用的包名和檔案名稱,其次需要擷取到你這個檔案的存取權限。從技術上來說如果你存放的檔案開放了檔案讀取許可權其他應用程式就能讀取到,除非是你把檔案設定為可讀寫的,要不然其他程式是無法讀取你的檔案的,所以檔案許可權Context.MODE_PRIVATE是必須要設定的。
儲存到外部儲存:儲存到外部儲存首先要檢查外部儲存是否存在並有剩餘空間,因為外部儲存有可能會被拔掉,或者正在串連著電腦,所以當你要在外部儲存儲存檔案的第一步就是檢查外部儲存是否掛在,可以通過調用getExternalStorageState()方法來查看外置儲存是否掛載,如果返回狀態是Environment.MEDIA_MOUNTED,則表明已經掛在,並且可以讀寫。例如下面的代碼:
/* Checks if external storage is available for read and write */publicboolean isExternalStorageWritable(){ String state =Environment.getExternalStorageState(); if(Environment.MEDIA_MOUNTED.equals(state)){ returntrue; } returnfalse;}/* Checks if external storage is available to at least read */publicboolean isExternalStorageReadable(){ String state =Environment.getExternalStorageState(); if(Environment.MEDIA_MOUNTED.equals(state)|| Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)){ returntrue; } returnfalse;}儘管外部儲存的檔案可以被使用者和其他程式訪問,但是對於外部儲存的檔案你需要分兩類對待:public files:這類檔案是完全開發的,對於其他應用程式或者使用者都可以訪問,當你的應用被卸載的時候這部分檔案也不會被刪除,比如你的拍照程式,使用者拍的照片不會因為使用者卸載了應用而刪除照片,還比如看視頻軟體,使用者下載下來的視頻也不能因為卸載二刪除。
private files:這類檔案屬於你的應用程式專有,對於其他應用程式無法使用,也沒有任何利用價值,雖然這部分檔案對使用者和其他程式是開放的。這類檔案在應用卸載的時候應該被刪掉,要不然會造成使用者空間的浪費,比如一些快取檔案,地圖資源等。
如果你想儲存一個公用的檔案到外部儲存,你可以通過Environment.java中的:public static File getExternalStoragePublicDirectory (String type)方法擷取外部儲存的公用目錄,公用目錄有幾種類型,根據你輸入的type返回不同的檔案夾,type類型有:
| public static String |
DIRECTORY_ALARMS |
標準的鈴聲目錄 |
| public static String |
DIRECTORY_DCIM |
相機拍照或錄影檔案的儲存目錄 |
| public static String |
DIRECTORY_DOWNLOADS |
下載目錄 |
| public static String |
DIRECTORY_MOVIES |
電影目錄 |
| public static String |
DIRECTORY_MUSIC |
音樂目錄 |
| public static String |
DIRECTORY_NOTIFICATIONS |
提示音目錄 |
| public static String |
DIRECTORY_PICTURES |
圖片目錄 |
| public static String |
DIRECTORY_PODCASTS |
播客目錄 |
| public static String |
DIRECTORY_RINGTONES |
鈴聲目錄 |
大家最常見的DIRECTORY_PICTURES目錄是:/mnt/sdcard/Pictures,比如你想要儲存一張圖片,要在外部存放圖片的公用目錄建立一個圖片檔案:
publicFile getAlbumStorageDir(String albumName){ // Get the directory for the user‘s public pictures directory. File file =newFile(Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_PICTURES), albumName); if(!file.mkdirs()){ Log.e(LOG_TAG,"Directory not created"); } return file;}
如果你想要儲存私人類型的資料到外部儲存上,可以通過調用Context.java中的:
public abstract File getExternalFilesDir (String type) 方法擷取外部儲存路徑,路徑是:
/mnt/sdcard/Android/data/data/your_package/type ,type同上,根據你想要儲存的檔案類型選擇,下面是建立存放私人圖片檔案的例子:
publicFile getAlbumStorageDir(Context context,String albumName){ // Get the directory for the app‘s private pictures directory. File file =newFile(context.getExternalFilesDir( Environment.DIRECTORY_PICTURES), albumName); if(!file.mkdirs()){ Log.e(LOG_TAG,"Directory not created"); } return file;}
如果type中沒有你需要的類型,你可以輸入null,此時返回的是你的應用程式外部儲存目錄的私人目錄的根目錄。
注意:通過getExternalFilesDir(String type) 方法建立的檔案在使用者清除資料或者在應用卸載的時候會被系統清除掉,getExternalStoragePublicDirectory(String type) 方法建立的檔案則不會。另外,無論你用哪一種方法建立應用程式外部隱藏檔,注意一下type類型的正確性,以便於系統處理的時候能夠正確處理,比如你儲存的一個檔案是鈴聲類型,在DIRECTORY_RINGTONES下,系統MediaScanner在進行多媒體掃描的時候會把這個檔案分類為鈴聲而不是音樂。
查詢剩餘空間:
如果你提前知道你要儲存的檔案大小,你就可以通過File.getFreeSpace()或者File.getTotalSpace()方法來估算儲存空間是否能夠容納,這樣就可以避免在沒有足夠的儲存空間時出現IOException。然而有的時候通過File.getFreeSpace()擷取的可用空間不一定就有那麼多供你使用,如果通過File.getFreeSpace()擷取的大小比你的檔案大幾M或者檔案系統有大於10%的剩餘空間,這時儲存檔案可能能夠正常進行,否則可能就會儲存失敗。
注意:在你儲存檔案之前,你不需要檢查可用空間,而是在寫入檔案的時候捕獲IOException,用這種方法來代替空間大小的檢查,如果你不知道你需要多少空間。
刪除檔案:當你不再需要一個檔案時你需要刪除它,最直接的方法就是直接調用File.delete()方法來刪除。如果這個檔案被儲存在內部儲存上,你也可以調用Context.deleteFile(String name)方法類刪除檔案。
在使用者卸載你的應用的時候Android系統會刪除你的一下檔案:1、所有儲存在內部儲存的檔案;2、所有儲存在getExternalFilesDir()目錄的外部隱藏檔;
注意:你需要定期手動清理通過getCacheDir()緩衝的檔案和不再需要的檔案。
總結:以上講解了Android系統中檔案儲存的相關知識,檔案儲存根據儲存位置分為外部儲存和內部儲存,根據開放性和對應用程式的可用性分為私人類型和公有類型,還有檔案儲存的方法和一些注意事項,網友們有什麼疑惑敬請留言或者回複我的公眾號:coder_online。
大家如果對編程感興趣,想瞭解更多的編程知識,解決編程問題,想要系統學習某一種開發知識,我們這裡有java高手,C++/C高 手,windows/Linux高手,android/ios高手,請大家關注我的公眾號:程式員互動聯盟or coder_online,大牛線上為您提供服務。
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
Android資料儲存之檔案儲存