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類型有:

大家最常見的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,大牛在線為您提供服務。

image010-258x250


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM