Android內部存儲與外部存儲解析

Android開發的過程中。經常會涉及到存儲,之前一直沒有一個整體的概念,這篇文章就是進行一個知識點的梳理。

Android的存儲有:內部存儲、外部存儲。

想要了解這兩個概念,我們先將開發軟件中的DDMS打開,看File Explorer,如下:

這裏寫圖片描述

1、內部存儲

上邊的data文件夾,就是內部存儲。data文件夾中有兩個重要的文件夾app、data。
  app文件夾存放着我們所有已安裝的軟件的apk文件。
  data文件夾存放以包名命名的文件夾。每個文件夾裏是:
    /data/data/包名/shared_prefs
    /data/data/包名/databases
    /data/data/包名/files
    /data/data/包名/cache
  這四個文件夾,其中SharePreferenced的數據就是存在shared_prefs中。軟件中的數據庫文件就是存在databases中,普通文件存在files中,緩存存在cache中。

在內部存儲中的數據,當相關的軟件刪除時,會被同時刪除。

2、外部存儲

圖中的mnt文件夾就是外部存儲,不同的手機生產廠商對應的文件夾還可能是storage文件夾。在storage文件夾中還有一個文件夾sdcard。這個就是我們平時調用獲取外部存儲api時獲取文件夾。在這個文件夾中公有目錄和私有目錄。公有目錄有九大類。私有目錄只有Android這一個,裏邊也是以包名爲目錄的。

  在很多文章中說,內部存儲就是手機自帶的內存、手機出廠時已經有的內存。外部存儲就是通過擴展SD卡的功能後增加的存儲卡,這種是不正確的。
  早期的Android設備,的確內部存儲時自帶的、固定的。但是後來的手機將自身的存儲擴展到了8G以及更高,許多手機也不再提供擴展SD卡功能。這時就只是在概念上把手機的存儲劃出了內部存儲和外部存儲。所以不管有沒有SD卡,都有內部存儲和外部存儲。但是不管什麼情況,訪問內部存儲和外部存儲都用的同一套Android Api。

在外部存儲中的數據,當卸載軟件時,該軟件存在私有目錄/data/storage/Android/data/包名/ 下的數據將全部刪掉。軟件存在公有目錄下的數據不會被刪掉。

3、存儲空間的操作

操作內部存儲空間和外部存儲空間的私有目錄時,以context獲取的。操作外部存儲空間時,以Environmnet獲取。方法總結如下:

內部存儲

目錄 方法
/data/data/包名/files context.getFilesDir()
/data/data/包名/cache context.getCacheDir()


外部存儲

目錄 方法
根目錄 Environment.getExternalStorageDirectory()
公有目錄(九大公有目錄) Environment.getExternalStoragePublicDirectory(String type)
私有目錄
/data/storage/Android/data/包名/files
context.getExternalFilesDir(String type)
私有目錄
/data/storage/Android/data/包名/cache
context.getExternalCacheDir()


其中,公有目錄的type類型,我們查看源碼:

/**
 * Get a top-level shared/external storage directory for placing files of a
 * particular type. This is where the user will typically place and manage
 * their own files, so you should be careful about what you put here to
 * ensure you don't erase their files or get in the way of their own
 * organization.
 * <p>
 * On devices with multiple users (as described by {@link UserManager}),
 * each user has their own isolated shared storage. Applications only have
 * access to the shared storage for the user they're running as.
 * </p>
 * <p>
 * Here is an example of typical code to manipulate a picture on the public
 * shared storage:
 * </p>
 * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
 * public_picture}
 *
 * @param type The type of storage directory to return. Should be one of
 *            {@link #DIRECTORY_MUSIC}, {@link #DIRECTORY_PODCASTS},
 *            {@link #DIRECTORY_RINGTONES}, {@link #DIRECTORY_ALARMS},
 *            {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_PICTURES},
 *            {@link #DIRECTORY_MOVIES}, {@link #DIRECTORY_DOWNLOADS},
 *            {@link #DIRECTORY_DCIM}, or {@link #DIRECTORY_DOCUMENTS}. May not be null.
 * @return Returns the File path for the directory. Note that this directory
 *         may not yet exist, so you must make sure it exists before using
 *         it such as with {@link File#mkdirs File.mkdirs()}.
 */
 public static File getExternalStoragePublicDirectory(String type) {
     throwIfUserRequired();
     return sCurrentUser.buildExternalStoragePublicDirs(type)[0];
 }

可以看出九種類型是:

類型 意義
Environment.DIRECTORY_MUSIC 音樂保存的位置
Environment.DIRECTORY_PODCASTS 用於保存podcast(博客)的音頻文件
Environment.DIRECTORY_RINGTONES 保存鈴聲的位置
Environment.DIRECTORY_ALARMS 警報的鈴聲
Environment.DIRECTORY_NOTIFICATIONS 通知音保存的位置
Environment.DIRECTORY_PICTURES 下載的圖片保存的位置
Environment.DIRECTORY_MOVIES 電影保存的位置
Environment.DIRECTORY_DOWNLOADS 下載文件保存的位置
Environment.DIRECTORY_DCIM 相機拍攝的圖片和視頻保存的位置



其中,context.getExternalFilesDir(String type)的類型有7種,看主要源碼:

/**
 * @param type The type of files directory to return. May be {@code null}
 *  for the root of the files directory or one of the following
 *            constants for a subdirectory:
 *            {@link android.os.Environment#DIRECTORY_MUSIC},
 *            {@link android.os.Environment#DIRECTORY_PODCASTS},
 *            {@link android.os.Environment#DIRECTORY_RINGTONES},
 *            {@link android.os.Environment#DIRECTORY_ALARMS},
 *            {@link android.os.Environment#DIRECTORY_NOTIFICATIONS},
 *            {@link android.os.Environment#DIRECTORY_PICTURES}, or
 *            {@link android.os.Environment#DIRECTORY_MOVIES}.
 * @return the absolute path to application-specific directory. May return
 *         {@code null} if shared storage is not currently available.
 * @see #getFilesDir
 * @see #getExternalFilesDirs(String)
 * @see Environment#getExternalStorageState(File)
 * @see Environment#isExternalStorageEmulated(File)
 * @see Environment#isExternalStorageRemovable(File)
 */
 @Nullable
 public abstract File getExternalFilesDir(@Nullable String type);

可以看出七種類型是:

類型 意義
Environment.DIRECTORY_MUSIC 音樂保存的位置
Environment.DIRECTORY_PODCASTS 用於保存podcast(博客)的音頻文件
Environment.DIRECTORY_RINGTONES 保存鈴聲的位置
Environment.DIRECTORY_ALARMS 警報的鈴聲
Environment.DIRECTORY_NOTIFICATIONS 通知音保存的位置
Environment.DIRECTORY_PICTURES 下載的圖片保存的位置
Environment.DIRECTORY_MOVIES 電影保存的位置

注意:這個方法是可以傳一個null的參數的,表示獲取的是當前目錄。如果傳入類型,則獲取的是對應的子目錄。



下邊給出一個對上邊講述方法進行運用的一個工具類:

import android.content.Context;
import android.os.Environment;

public class SDUtil {

    // 判斷SD卡是否被掛載
    public static boolean isSDCardMounted() {
        return Environment.MEDIA_MOUNTED.equals(
                Environment.getExternalStorageState());
    }

    // 獲取內部存儲文件的存儲路徑
    public static String getFilePath(Context context) {
        return context.getFilesDir().getPath();
    }

    // 獲取內部存儲緩存的存儲路徑
    public static String getCachePath(Context context) {
        return context.getCacheDir().getPath();
    }

    // 獲取外部存儲根的存儲路徑,因爲不同的商家外部存儲的絕對路徑可能不同,所以用相對路徑進行操作
    public static String getExternalPath() {
        if (isSDCardMounted()){
            return Environment.getExternalStorageDirectory().getAbsolutePath();
        }
        return null;
    }

    // 獲取外部存儲公共目錄的存儲路徑
    public static String getExternalPublicPath(String type) {
        if (isSDCardMounted()){
            return Environment.getExternalStoragePublicDirectory(type).getAbsolutePath();
        }
        return null;
    }

    // 獲取外部存儲私有目錄的文件的存儲路徑
    public static String getExternalFilePath(Context context,String type) {
        if (isSDCardMounted()){
            return context.getExternalFilesDir(type).getAbsolutePath();
        }
        return null;
    }

    // 獲取外部存儲私有目錄的緩存的存儲路徑
    public static String getExternalCachePath(Context context,String type){
        if (isSDCardMounted()){
            return context.getExternalCacheDir().getAbsolutePath();
        }
        return null;
    }

}

這篇博客是一篇學習總結,如有錯誤的地方,請大家指正。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章