Skip to content

Most visited

Recently visited

navigation

儲存檔案

Android 使用的檔案系統類似於其他平台上的磁碟式檔案系統。 本課程將說明如何透過 Android 檔案系統,使用 File API 讀取並寫入檔案。

File 物件適用於以從頭到尾的順序,無一略過地讀取或寫入大量資料。 該物件的用途很廣,例如非常適用於影像檔案或透過網路交換的項目。

本課程將顯示如何在您的應用程式中執行與檔案相關的基本任務。本課程假設您已熟悉 Linux 檔案系統的基本概念,以及 java.io 中的標準檔案輸入/輸出 API。

選擇內部或外部儲存空間

所有 Android 裝置都有兩個檔案儲存區域:「內部」與「外部」儲存空間。這些名稱源自 Android 發展的初期,當時大多數裝置都提供內建靜態記憶體 (內部儲存空間),以及諸如 micro SD 卡等卸除式儲存媒體 (外部儲存空間)。有些裝置將永久儲存空間分為「內部」與「外部」分割區,因此即使沒有卸除式儲存媒體,也始終存在兩個儲存空間,不論外部儲存空間是否為卸除式媒體,API 行為都相同。以下清單將概述每個儲存空間的狀況。

內部儲存空間:

  • 裝置始終具備內部儲存空間。
  • 依預設,只有您的應用程式能存取此空間內儲存的檔案。
  • 使用者解除安裝您的應用程式時,系統會從內部儲存空間移除您應用程式的所有檔案。

若您希望確保使用者與其他應用程式都無法存取您的檔案,使用內部儲存空間是最佳選擇。

外部儲存空間:

  • 裝置並非始終具備外部儲存空間,因為使用者可以將外部儲存空間掛接為 USB 儲存裝置,在某些情況下也可以從裝置上移除外部儲存空間。
  • 其他應用程式可以讀取外部儲存空間,因此您可能無法對該空間內儲存的檔案遭讀取的情況進行控制。
  • 若使用者解除安裝您的應用程式,只有在您將應用程式的檔案儲存在 getExternalFilesDir() 的目錄中時,系統才會從外部儲存空間移除您應用程式的檔案。

對於不需要存取限制的檔案,以及您希望與其他應用程式共用的檔案,或允許使用者使用電腦存取的檔案,外部儲存空間是最佳的儲存位置。

秘訣:雖然應用程式依預設會安裝在內部儲存空間,但是您可以在宣示說明中指定 android:installLocation 屬性,以便可以將應用程式安裝在外部儲存空間。 在 APK 的大小很大,且使用者的外部儲存空間大於內部儲存空間時,使用者非常喜歡使用該選項。 如需詳細資訊,請參閱應用程式安裝位置

取得外部儲存空間的權限

若要寫入至外部儲存空間,您必須在宣示說明檔案中要求 WRITE_EXTERNAL_STORAGE 權限:

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

注意: 目前,所有應用程式無需特殊權限即可讀取外部儲存空間。 但是,此狀況在將來的版本中將有所變更。若您的應用程式需要讀取外部儲存空間 (但不寫入該空間),您需要宣告 READ_EXTERNAL_STORAGE 權限。 若要確保您的應用程式仍以預期方式運作,您應立即宣告此權限,然後變更即會生效。

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

但是,若您的應用程式使用 WRITE_EXTERNAL_STORAGE 權限,則也以隱含方式具備外部儲存空間讀取權限。

您無需任何權限即可將檔案儲存在內部儲存空間。 您的應用程式始終具備內部儲存空間目錄中檔案的讀取與寫入權限。

將檔案儲存在內部儲存空間

將檔案儲存在內部儲存空間時,您可以呼叫以下兩種方法的其中之一,以 File 擷取相應目錄:

getFilesDir()
傳回代表您應用程式所用內部目錄的 File
getCacheDir()
傳回代表您應用程式暫存快取檔案所用內部目錄的 File。 請確保於不再需要檔案時刪除檔案,並針對您在任何指定時間所用的記憶體數量實作合理的大小限制,例如 1MB。 若系統所用的儲存空間開始不足,可能會刪除您的快取檔案而不提供警告。

若要在上述其中一個目錄中建立新檔案,可以使用 File() 建構函式,然後傳送會指定您內部儲存空間目錄的 File (由上述其中一種方法提供)。 例如:

File file = new File(context.getFilesDir(), filename);

或者,您可以呼叫 openFileOutput(),以取得寫入內部目錄中檔案的 FileOutputStream。 例如,以下展示了如何將某些文字寫入至檔案:

String filename = "myfile";
String string = "Hello world!";
FileOutputStream outputStream;

try {
  outputStream = openFileOutput(filename, Context.MODE_PRIVATE);
  outputStream.write(string.getBytes());
  outputStream.close();
} catch (Exception e) {
  e.printStackTrace();
}

或者,若您需要快取某些檔案,應改用 createTempFile()。例如,以下方法會從 URL 中擷取檔案名稱,然後在您應用程式的內部快取目錄中建立具有該名稱的檔案:

public File 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;
}

注意: 您應用程式的內部儲存空間目錄由位於 Android 檔案系統特殊位置的應用程式套件名稱指定。嚴格來說,若將檔案模式設為可讀取,則其他應用程式可以讀取您的內部檔案。 但是,其他應用程式也需要知道您的應用程式套件名稱與檔案名稱。 除非您將檔案明確設為可讀取或可寫入,否則其他應用程式無法瀏覽您的內部目錄,也沒有讀取或寫入存取權。 因此,只要您針對內部儲存空間中的檔案使用 MODE_PRIVATE,其他應用程式將永遠無法存取這些檔案。

將檔案儲存在外部儲存空間

由於可能不具備外部儲存空間—例如使用者將儲存裝置掛接至 PC,或移除提供外部儲存空間的 SD 卡—,因此您始終應先驗證磁碟區可用,然後再對其執行存取。 您可以呼叫 getExternalStorageState(),以查詢外部儲存空間狀態。 若傳回的狀態等於 MEDIA_MOUNTED,則可以讀取並寫入檔案。 例如,以下方法可用於判斷儲存空間的可用性:

/* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable() {
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state)) {
        return true;
    }
    return false;
}

/* Checks if external storage is available to at least read */
public boolean isExternalStorageReadable() {
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state) ||
        Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
        return true;
    }
    return false;
}

雖然使用者與其他應用程式可以修改外部儲存空間,但是可在外部儲存空間儲存兩種類別的檔案:

公用檔案
這些檔案將供其他應用程式及使用者自由使用。 若使用者解除安裝您的應用程式,這些檔案仍可供使用者使用。

例如,由您的應用程式拍攝的相片或下載的其他檔案都是公用檔案。

私用檔案
這些檔案本屬於您的應用程式,在使用者解除安裝您的應用程式時應予以刪除。雖然嚴格來說,由於這些檔案位於外部儲存空間,因此可供使用者與其他應用程式存取,但實際上這些檔案對於您應用程式之外的使用者並無價值。使用者解除安裝您的應用程式時,系統會刪除您應用程式外部私用目錄中的所有檔案。

例如,您的應用程式下載的附加資源,或暫存媒體檔案都是私用檔案。

若您希望將公用檔案儲存在外部儲存空間,請使用 getExternalStoragePublicDirectory() 方法取得代表外部儲存空間內相應目錄的 File。 該方法採用對要儲存的檔案類型進行指定 (以便能合理區分這些檔案與其他公用檔案) 的引數,諸如 DIRECTORY_MUSICDIRECTORY_PICTURES。 例如:

public File getAlbumStorageDir(String albumName) {
    // Get the directory for the user's public pictures directory.
    File file = new File(Environment.getExternalStoragePublicDirectory(
            Environment.DIRECTORY_PICTURES), albumName);
    if (!file.mkdirs()) {
        Log.e(LOG_TAG, "Directory not created");
    }
    return file;
}

若您希望儲存應用程式私用的檔案,可以呼叫 getExternalFilesDir(),然後向其傳送名稱 (表示您希望使用的目錄類型),從而擷取相應目錄。 以此方式建立的每個目錄都會新增至父系目錄 (該目錄會封裝您應用程式的所有外部儲存空間檔案),並在使用者解除安裝您的應用程式時由系統刪除。

例如,以下所示的方法可用於建立個別相簿的目錄:

public File getAlbumStorageDir(Context context, String albumName) {
    // Get the directory for the app's private pictures directory.
    File file = new File(context.getExternalFilesDir(
            Environment.DIRECTORY_PICTURES), albumName);
    if (!file.mkdirs()) {
        Log.e(LOG_TAG, "Directory not created");
    }
    return file;
}

若預先定義的任何子目錄名稱都不適用於您的檔案,您可以改為呼叫 getExternalFilesDir() 並傳送 null。此操作 會傳回外部儲存空間內您應用程式私用目錄的根目錄。

請記住,getExternalFilesDir() 會在使用者解除安裝您的應用程式時所刪除的目錄中建立目錄。若您希望要儲存的檔案在使用者解除安裝您的應用程式後仍可用—例如您的應用程式是相機,而使用者希望保留相片—,應改用 getExternalStoragePublicDirectory()

不論是將 getExternalStoragePublicDirectory() 用於共用的檔案,還是將 getExternalFilesDir() 用於您應用程式私用的檔案,請務必使用由 API 常數 (例如 DIRECTORY_PICTURES) 提供的目錄名稱。 這些目錄名稱可確保系統正確處理檔案。 例如,系統媒體掃描程式會將 DIRECTORY_RINGTONES 中儲存的檔案視為鈴聲,而非音樂。

查詢可用空間

若您預先知道要儲存的資料量,可以呼叫 getFreeSpace()getTotalSpace() 以探明在不會導致 IOException 的情況下空間是否充足。 上述方法可分別提供儲存磁碟區內目前可用空間量與空間總量。 該資訊還可以用於避免填充的儲存磁碟區超過特定臨界值。

但是,系統不保證您可以寫入 getFreeSpace() 所示的位元組數量。 若傳回的數值較您要儲存的資料量略大,或檔案系統的已使用空間不到 90%,則繼續寫入可能是安全的。否則,可能不應寫入儲存空間。

注意:在儲存檔案之前,您無需檢查可用空間量。 您可以嘗試立即寫入檔案,然後在發生 IOException 時執行捕捉即可。 若您不知道需要的確切空間量,可能需要執行該作業。 例如,若您在儲存檔案之前,將 PNG 影像轉化為 JPEG 以變更檔案的編碼,就不會預先知道檔案的大小。

刪除檔案

不再需要檔案時,應一律刪除檔案。最直接的檔案刪除方式是讓開啟的檔案參考在自身上呼叫 delete()

myFile.delete();

若檔案儲存在內部儲存空間,您也可以呼叫 deleteFile(),讓 Context 尋找並刪除檔案:

myContext.deleteFile(fileName);

注意:使用者解除安裝您的應用程式時,Android 系統會刪除以下檔案:

  • 您在內部儲存空間儲存的所有檔案
  • 您使用 getExternalFilesDir() 在外部儲存空間儲存的所有檔案。

但是,您應定期手動刪除使用 getCacheDir() 建立的所有快取檔案,並定期刪除不再需要的其他檔案。

This site uses cookies to store your preferences for site-specific language and display options.

Hooray!

This class requires API level or higher

This doc is hidden because your selected API level for the documentation is . You can change the documentation API level with the selector above the left navigation.

For more information about specifying the API level your app requires, read Supporting Different Platform Versions.

Take a one-minute survey?
Help us improve Android tools and documentation.