1. 程式人生 > 其它 >【專業技術】Android資料儲存之檔案儲存

【專業技術】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系統中檔案儲存的相關知識,檔案儲存根據儲存位置分為外部儲存和內部儲存,根據開放性和對應用程式的可用性分為私有型別和公有型別,還有檔案儲存的方法和一些注意事項