Android資料儲存之Android 6.0執行時許可權下檔案儲存的思考

總李寫程式碼發表於2016-12-07

前言:

     在我們做App開發的過程中基本上都會用到檔案儲存,所以檔案儲存對於我們來說是相當熟悉了,不過自從Android 6.0釋出之後,基於執行時許可權機制訪問外接sdcard是需要動態申請許可權,所以以往直接sdcard根目錄上直接新建了一個xxx/cache/目錄來做檔案儲存就會不是那麼容易控制了,所以有必要重新認識一下Android檔案儲存的相關知識了。

背景:

   有關外接sdcard的讀寫許可權

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

   在Android 6.0 之前只要申明瞭上述兩個許可權就可以放心大膽的在sdcard上進行讀寫了,可惜Android 6.0之後就需要動態申請讀寫許可權了,所以我們該如何適配Android 6.0來進行檔案儲存。首先我們在使用檔案儲存的時候儘量做到以下幾點:

  • 不要隨意佔用使用者的內建儲存

  • 不要隨意在SD卡上新建目錄,應該放置自己應用包名對應的擴充套件儲存目錄下,解除安裝App時可以被自動清除。

  • 對佔用的磁碟空間有上限,並按照一定的策略進行清除,比如DiskLru演算法等。

Android檔案儲存目錄:

1.)應用私有儲存(內建儲存)

訪問方式 詳細路徑 是否需要申請許可權

Context.getFileDir();獲取內建儲存下的檔案目錄,可以用來儲存不能公開給其他應用的一些敏感資料如使用者個人資訊

 /data/data/應用包名/files/  否

Context.getCacheDir();獲取內建儲存下的快取目錄,可以用來儲存一些快取檔案如圖片,當內建儲存的空間不足時將系統自動被清除

 /data/data/應用包名/cache/ 否 

注意:

 由於這裡使用的是Android 手機內建儲存,如果手機沒有獲得root許可權的話檔案瀏覽器是無法訪問的,同樣這種儲存也會隨之app被刪除而被刪除。

2.)應用擴充套件儲存(SD卡)

訪問方式 路徑詳情 是否需要申請許可權

 Context.getExternalFilesDir();獲取SD卡上的檔案目錄,

 SDCard/Android/data/應用包名/files/

 API < 19:是

API >= 19:否

 Context.getExternalCacheDir();獲取SD卡上的快取目錄,可以用來儲存一些快取檔案如圖片

 SDCard/Android/data/應用包名/cache/

 API < 19:是

API >= 19:否

 注意:

   由於儲存在sdcard上所以儘量不要存在敏感資料比如使用者資訊等,這裡的檔案也會隨著app 被刪除而被刪除。

3.)公共儲存(SD卡)

訪問方式 路徑詳情 是否需要申請許可權
Environment.getExternalStorageDirectory();獲取sdcard根目錄 SDCard/xxx資料夾名字/

注意:

  有時我們也是需要儲存一些公共檔案,而且希望這些檔案能夠不隨著App被刪除而被刪除,例如我們錄製的視訊或者下載的音樂等。由於這個目錄可以被任何app訪問,所以我們在使用的時候是需要申請許可權的。

相容Android 6.0 檔案快取實現

  前提:這裡主要處理一些非永久儲存資料,需要永久儲存的資料儘量還是要選擇sdcard 公共儲存方式的。

1.)獲取快取根目錄

  /**
     * 獲取app的根目錄
     *
     * @return 檔案快取根路徑
     */
    public static String getDiskCacheRootDir() {
        File diskRootFile;
        if (existsSdcard()) {
            diskRootFile = LeeApplication.getApp().getExternalCacheDir();
        } else {
            diskRootFile = LeeApplication.getApp().getCacheDir();
        }
        String cachePath;
        if (diskRootFile != null) {
            cachePath = diskRootFile.getPath();
        } else {
            throw new IllegalArgumentException("disk is invalid");
        }
        return cachePath;
    }

這裡需要判斷sdcard是否可用

    /**
     * 判斷外接sdcard是否可以正常使用
     *
     * @return
     */
    public static Boolean existsSdcard() {
        return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) || !Environment.isExternalStorageRemovable();
    }

2.)獲取指定功能的目錄

  /**
     * 獲取相關功能業務目錄
     *
     * @return 檔案快取路徑
     */
    public static String getDiskCacheDir(String dirName) {
        String dir = String.format("%s/%s/", getDiskCacheRootDir(), dirName);
        File file = new File(dir);
        if (!file.exists()) {
            boolean isSuccess = file.mkdirs();
            if (isSuccess) {
                Log.d(TAG, "dir mkdirs success");
            }
        }
        return file.getPath();
    }

在日常開發過程中,我們需要不同的檔案放在不同的目錄下,比如:log日誌檔案需要放在log檔案下,就可以通過上面的方法傳入“log”獲取該業務功能的資料夾。

3.)獲取指定功能檔案路徑

    /**
     * 獲取log日誌根目錄
     * @return
     */
    public  static String getLogDir(){
        return getDiskCacheDir(LOG);
    }

    /**
     * 根據logName 獲取log檔案全路徑
     * @param logName
     * @return
     */
    public  static String getLogFilePath(String logName){
        return  getLogDir()+logName;
    }

 總結:

      今天總結了Android的檔案儲存及在6.0上的適配問題,最近突然覺得自己有太多的知識需要學習了,也許由於現在的經濟大環境導致網際網路遇到了資本寒冬了,其實對於我來說2012年已經經歷過一次了,對於技術人員來說應該冷靜的看待這個問題,需要做的就是在寒冬裡播種希望,那就是學習。以此共勉之~

 

相關文章