Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android文件存儲

android文件存儲

編輯:關於Android編程

所有的Android設備均有兩個文件存儲區域:”internal” 與 “external” 。 這兩個名稱來自於早先的Android系統,當時大多設備都內置了不可變的內存(internal storage)及一個類似於SD card(external storage)這樣的可卸載的存儲部件。之後有一些設備將”internal” 與 “external” 都做成了不可卸載的內置存儲,雖然如此,但是這一整塊還是從邏輯上有被劃分為”internal”與”external”的。只是現在不再以是否可卸載進行區分了。


兩者的區別:

Internal storage
- 總是可用的
- 這裡的文件默認只能被我們的app所訪問。
- 當用戶卸載app的時候,系統會把internal內該app相關的文件都清除干淨。
- Internal是我們在想確保不被用戶與其他app所訪問的最佳存儲區域。

External storage
- 並不總是可用的,因為用戶有時會通過USB存儲模式掛載外部存儲器,當取下掛載的這部分後,就無法對其進行訪問了。
- 是大家都可以訪問的,因此保存在這裡的文件可能被其他程序訪問。
- 當用戶卸載我們的app時,系統僅僅會刪除external根目錄(getExternalFilesDir())下的相關文件。
- External是在不需要嚴格的訪問權限並且希望這些文件能夠被其他app所共享或者是允許用戶通過電腦訪問時的最佳存儲區域。

Note:盡管app是默認被安裝到internal storage的,我們還是可以通過在程序的manifest文件中聲明android:installLocation 屬性來指定程序安裝到external storage。當某個程序的安裝文件很大且用戶的external storage空間大於internal storage時,用戶會傾向於將該程序安裝到external storage。

對於android的存儲,其實就是使用java對文件進行存儲或讀取

內存存儲

當保存文件到internal storage時,可以通過執行下面兩個方法之一來獲取合適的目錄作為 FILE 的對象:
- getFilesDir() : 返回一個File,代表了我們app的internal目錄。
- getCacheDir() : 返回一個File,代表了我們app的internal緩存目錄。請確保這個目錄下的文件能夠在一旦不再需要的時候馬上被刪除,並對其大小進行合理限制,例如1MB 。系統的內部存儲空間不夠時,會自行選擇刪除緩存文件。

可以使用File() 構造器在那些目錄下創建一個新的文件,然後進行存儲;同樣,也可以執行openFileOutput() 獲取一個 FileOutputStream 用於寫文件到internal目錄。

向內部存儲中寫內容:

    //文件默認會存儲到/data/data/package/files中;
    private void write2FileMethod1(String data, int mode) {
        FileOutputStream outputStream;
        try {
            outputStream = openFileOutput(FILE_NAME, mode);
            outputStream.write(data.getBytes("UTF-8"));
            outputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void write2FileMethod2(String data) {
        FileOutputStream outputStream;
        try {
            outputStream = new FileOutputStream(getFile());
            outputStream.write(data.getBytes());
            outputStream.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

   private File getFile() {
        return new File(this.getFilesDir(), FILE_NAME);
    }

從內部存儲中讀取內容

    private void readFromFile() {
        FileInputStream in;
        ByteArrayOutputStream bout;
        byte[]buf = new byte[1024];
        bout = new ByteArrayOutputStream();
        int length;
        try {
            in = this.openFileInput(FILE_NAME);
            while((length = in.read(buf))!=-1){
                bout.write(buf,0,length);
            }
            byte[] content = bout.toByteArray();
            mDataTv.setText(new String(content,"UTF-8"));
            in.close();
            bout.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

外部存儲

為確保外置存儲可用,我們一般會進行判斷:

/* 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;
}

有的手機會有外置存儲和內置存儲的區分,即手機自帶的外置存儲和擴展的外置存儲的分別,這可以通過某些方法來區分。

盡管external storage對於用戶與其他app是可修改的,我們可能會保存下面兩種類型的文件。
- Public files :這些文件對與用戶與其他app來說是public的,當用戶卸載我們的app時,這些文件應該保留。例如,那些被我們的app拍攝的圖片或者下載的文件。
- Private files: 這些文件完全被我們的app所私有,它們應該在app被卸載時刪除。盡管由於存儲在external storage,那些文件從技術上而言可以被用戶與其他app所訪問,但實際上那些文件對於其他app沒有任何意義。因此,當用戶卸載我們的app時,系統會刪除其下的private目錄。例如,那些被我們的app下載的緩存文件。

想要將文件以public形式保存在external storage中,請使用getExternalStoragePublicDirectory()方法來獲取一個 File 對象,該對象表示存儲在external storage的目錄。這個方法會需要帶有一個特定的參數來指定這些public的文件類型,以便於與其他public文件進行分類。參數類型包括DIRECTORY_MUSIC 或者 DIRECTORY_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;
}

想要將文件以private形式保存在external storage中,可以通過執行getExternalFilesDir() 來獲取相應的目錄,並且傳遞一個指示文件類型的參數。每一個以這種方式創建的目錄都會被添加到external storage封裝我們app目錄下的參數文件夾下(如下則是albumName)。這下面的文件會在用戶卸載我們的app時被系統刪除。如下示例:

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. 它會返回app在external storage下的private的根目錄。

getExternalFilesDir() 方法會創建的目錄會在app被卸載時被系統刪除。如果我們的文件想在app被刪除時仍然保留,請使用getExternalStoragePublicDirectory()

    /**
     * 如果想更換存儲路徑請更換
     * @param childFile
     * @return
     */
    private File getFile(String childFile) {
        return new File(getExternalFilesDir(childFile), FILE_NAME);
    }
    private void write2File(String fileName, String data, boolean isAppend) {
        try {
            FileOutputStream outputStream = new FileOutputStream(getFile(fileName), isAppend);
            outputStream.write(data.getBytes());
            outputStream.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void readFromFile(String fileName) {
        if(!isExternalStorageReadAble()) {
            showToast("外置存儲不可讀");
            return;
        }
        ByteArrayOutputStream outputStream;
        byte[] buf = new byte[1024];
        outputStream = new ByteArrayOutputStream();
        int length;
        try {
            FileInputStream inputStream = new FileInputStream(getFile(fileName));
            while ((length = inputStream.read(buf)) != -1) {
                outputStream.write(buf, 0, length);
            }
            byte[] content = outputStream.toByteArray();
            mDataTv.setText(new String(content, "utf-8"));
            outputStream.close();
            inputStream.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

默認情況下,上述寫內容的時候是MODE_PRIVATE的,如果想要使用APPEND模式使用下方幾種方式:

/**
     * 追加文件:使用FileOutputStream,在構造FileOutputStream時,把第二個參數設為true
     */
    public static void method1(String file, String conent) {
        BufferedWriter out = null;
        try {
            out = new BufferedWriter(new OutputStreamWriter(
                new FileOutputStream(file, true)));
            out.write(conent);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    /**
     * 追加文件:使用FileWriter
     *
     * @param fileName
     * @param content
     */
    public static void method2(String fileName, String content) {
        try {
            // 打開一個寫文件器,構造函數中的第二個參數true表示以追加形式寫文件
            FileWriter writer = new FileWriter(fileName, true);
            writer.write(content);
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * 追加文件:使用RandomAccessFile
     *
     * @param fileName
     *            文件名
     * @param content
     *            追加的內容
     */
    public static void method3(String fileName, String content) {
        try {
            // 打開一個隨機訪問文件流,按讀寫方式
            RandomAccessFile randomFile = new RandomAccessFile(fileName, "rw");
            // 文件長度,字節數
            long fileLength = randomFile.length();
            // 將寫文件指針移到文件尾。
            randomFile.seek(fileLength);
            randomFile.writeBytes(content);
            randomFile.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

可以看出,其實讀或寫內存或外存的內容不過是將文件的路徑改變了而已。

關於刪除文件

在不需要使用某些文件的時候應刪除它。刪除文件最直接的方法是直接執行文件的delete()方法。
myFile.delete();
保存在內部存儲中的文件,也可以使用deleteFleece(fileName)來刪除:
myContext.deleteFile(fileName);

Note: 當用戶卸載我們的app時,android系統會刪除以下文件:
- 所有保存到internal storage的文件。
- 所有使用getExternalFilesDir()方式保存在external storage的文件。
然而,通常來說,我們應該手動刪除所有通過 getCacheDir() 方式創建的緩存文件,以及那些不會再用到的文件。

具體demo在項目中storage包名下

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved