Android儲存

weixin_33935777發表於2018-01-24

一、基本認識

所有的Android裝置都有兩個檔案儲存區域:“內部”和“外部”儲存。這兩個名稱來自早期的Android,當時大多數裝置都提供內建的固定的記憶體(內部儲存)即ROM(主要分三部分:系統儲存、系統快取、內部儲存)中的內部儲存部分,外加一個可移動的儲存介質,如SD卡(外部儲存)。現在的大部分裝置把固定不變的儲存空間分成“內部”和“外部”兩部分,這樣即使沒有可移動的儲存介質,也總會有兩個儲存空間,並且不管外部儲存器是可移動的,還是固定的,API的行為是相同的。

把手機連線電腦,能被電腦識別的部分就一定是外部儲存。

開啟DDMS,有一個File Explorer,如下:

9821298-0bfec9ccded9b6ae.png

這裡有三個資料夾需要我們重視,一個是data,一個是mnt,一個是storage,我們下面就詳細說說這三個資料夾。

1、記憶體(Memory)

RAM(隨機訪問儲存器),斷電後資料丟失。

2、內部儲存(InternalStorage)

data資料夾就是內部儲存,應用程式私有的,其他應用無法訪問。當我們開啟data資料夾之後(沒有root的手機不能開啟該資料夾),裡邊有兩個資料夾值得我們關注,如下:

9821298-76dae7f56949b5ea.png

app資料夾:存放著我們所有安裝的app的apk檔案。當我們除錯一個app的時候,可以看到控制檯輸出的內容,有一項是uploading……就是上傳我們的apk到這個資料夾,上傳成功之後才開始安裝。

data資料夾:這個資料夾裡邊都是一些包名,開啟這些包名之後我們會看到這樣的一些檔案:

  • /data/data/包名/shared_prefs
  • /data/data/包名/databases
  • /data/data/包名/files
  • /data/data/包名/cache

在使用sharedPreferenced的時候,將資料持久化儲存於本地,就是將xml檔案儲存於shared_prefs資料夾;App裡邊的資料庫檔案就儲存於databases資料夾中;普通資料儲存在files中;快取檔案儲存在cache資料夾中。

方法

  • Environment.getDataDirectory() /data
  • context.getFilesDir() /data/data/包名/files
  • context.getCacheDir() /data/data/包名/cache,機身記憶體不足時,檔案會被刪除

3、外部儲存(ExternalStorage)

任何有訪問許可權的應用均可以訪問修改,相對於裝置的內部儲存空間而言,會大很多,所以一般比較大的資料,均會存放在外部儲存中。寫入資料,你必須在清單檔案中申請WRITE_EXTERNAL_STORAGE許可權和READ_EXTERNAL_STORAGE(API 19開始,不再需要顯式宣告這兩個許可權,除非要讀寫其他應用的應用資料)。外部儲存一般就是我們上面看到的storage資料夾,當然也有可能是mnt檔案夾,這個不同廠家有可能不一樣。

一般來說,在storage資料夾中有一個sdcard資料夾,這個資料夾中的檔案又分為兩類,一類是公有目錄,還有一類是私有目錄,其中的公有目錄有九大類,比如DCIM、DOWNLOAD等這種系統為我們建立的資料夾,私有目錄就是Android這個資料夾,這個資料夾開啟之後裡邊有一個data資料夾,開啟這個data資料夾,裡邊有許多包名組成的資料夾(也可以被其他應用修改)。

建議App的資料應該儲存在外部儲存的私有目錄中該app的包名下,這樣當使用者解除安裝掉App之後,相關的資料會一併刪除,這樣有利於系統維護,也避免使用者的反感。如果你直接在/storage/sdcard目錄下建立了一個應用的資料夾,那麼當你刪除應用的時候,這個資料夾就不會被刪除。不建議往內部儲存中寫太多的資料,畢竟空間有限。

按照路徑的特徵,又可以將檔案儲存的路徑分為兩大類:路徑中含有包名的;路徑中不含有包名的。含有包名的路徑,因為和某個App有關,所以對這些資料夾的訪問都是呼叫Context裡邊的方法,而不含有包名的路徑,和某一個App無關,可以通過Environment中的方法來訪問。

開啟手機設定,選擇應用管理,選擇任意一個App,然後你會看到兩個按鈕,一個是清除快取,另一個是清除資料。清除資料清除的是內部儲存目錄中相應的files和cache資料夾中的檔案和外部儲存中相應的files和cache資料夾中的檔案。

方法:

  • Environment.getExternalStorageState() String 獲取SD卡狀態,Environment.MEDIA_MOUNTED為可用
  • Environment.getExternalStorageDirectory() 獲取外部儲存根目錄(/storage/sdcard0)
  • Environment.getExternalStoragePublicDirectory("folder1") /storage/sdcard0/folder1
  • Environment.getExternalStoragePublicDirectory(String type) 訪問公有九大目錄
  • File getExternalFilesDir(String type) /storage/sdcard/Android/包名/files
  • File getExternalCacheDir() /storage/sdcard/Android/包名/cache
  • getExternalFilesDir(null) /storage/Android/data/包名/files
  • getExternalFilesDir("caches") /storage/Android/data/包名/files/caches,當空間不足時,檔案不會實時被刪除,可能返回空物件

type型別:

文字
Environment.DIRECTORY_NOTIFICATIONS Notifications
Environment.DIRECTORY_PODCASTS Podcasts
Environment.DIRECTORY_RINGTONES Ringtones
Environment.DIRECTORY_ALARMS Alarms
Environment.DIRECTORY_PICTURES Pictures
Environment.DIRECTORY_MOVIES Movies
Environment.DIRECTORY_DOWNLOADS Download
Environment.Environment.DIRECTORY_DCIM DCIM
Environment.DIRECTORY_DOCUMENTS Documents

二、StatFs

用於獲取儲存空間

  • 建構函式 StatFs(String filePath)

API<18

  • getAvailableBlocks()
    檔案系統中可被應用程式使用的空閒儲存區塊的數量
  • getBlockCount()
    檔案系統中總的儲存區塊的數量
  • getBlockSize()
    檔案系統中每個儲存區塊的位元組數
  • getFreeBlocks()
    檔案系統中總的空閒儲存區塊的數量,包括保留的儲存區塊(不能被普通應用程式使用)

API>=18

  • getAvailableBlocksLong()
    檔案系統中可被應用程式使用的空閒儲存區塊的數量
  • getAvailableBytes()
    檔案系統中可被應用程式使用的空閒位元組數
  • getBlockCountLong()
    檔案系統中總的儲存區塊的數量
  • getBlockSizeLong()
    檔案系統中每個儲存區塊的位元組數
  • getFreeBlocksLong()
    檔案系統中總的空閒儲存區塊的數量,包括保留的儲存區塊(不能被普通應用程式使用)
  • getFreeBytes()
    檔案系統中總的空閒位元組數,包括保留的儲存區塊(不能被普通應用程式使用)
  • getTotalBytes()
    檔案系統支援的總的儲存位元組數

獲取SD卡的完整空間大小,返回MB

StatFs fs = new StatFs(getSDCardBaseDir());
long count = fs.getBlockCountLong();
long size = fs.getBlockSizeLong();
return count * size / 1024 / 1024;

往SD卡的公有目錄下儲存檔案

public static boolean saveFileToSDCardPublicDir(byte[] data, String type, String fileName) {
    BufferedOutputStream bos = null;
        if (isSDCardMounted()) {
           File file = Environment.getExternalStoragePublicDirectory(type);
            try {
                bos = new BufferedOutputStream(new FileOutputStream(new File(file, fileName)));
                bos.write(data);
                bos.flush();
                return true;
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return false;
}

從SD卡獲取檔案


 public static byte[] loadFileFromSDCard(String fileDir) {
        BufferedInputStream bis = null;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            bis = new BufferedInputStream(new FileInputStream(new File(fileDir)));
            byte[] buffer = new byte[8 * 1024];
            int c = 0;
            while ((c = bis.read(buffer)) != -1) {
                baos.write(buffer, 0, c);
                baos.flush();
            }
            return baos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                baos.close();
                bis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

參考文獻:

徹底理解android中的內部儲存與外部儲存
是時候弄清楚getExternalStorageDirectory()和getExternalFilesDir()的區別了
Android檔案儲存使用參考 - liaohuqiu

相關文章