在 Android 安裝 APP 時,系統會自動在手機內部規劃一個專屬的目錄 (app-specific) 來儲存 APP 資料,這個目錄就是 Internal Storage,儲存在這個目錄之外的就稱為 External Storage。 Internal Storage 只有安裝的 APP 可以存取,無法與其他 APP 共享資料,也無法使用手機內建的檔案管理 APP 瀏覽檔案,如果 APP 是您開發的話,可以使用 Android Studio 內建的 Device File Explorer 工具來瀏覽檔案。 當 APP 解除安裝時,資料也會一併刪除,而在 Android 10 (API 29) 及以上版本中,這些位置會進行加密處理,進一步提升資料安全性。適合用來儲存 APP 執行時會用到的必要檔案,或較機密的資料

Internal Storage 是儲存在手機內部儲存空間,主要有兩個類型,一個是儲存永久檔案,另一個是儲存快取檔案,兩者在使用上皆無需任何權限就可以操作這些檔案。 早期手機容量通常遠小於 SD 卡,所以不建議將太多的資料放在 Internal Storage,而應放在 External Storage,雖然現在手機容量通常都很大,但還是應該合理的使用 Internal Storage 的空間。

永久檔案

儲存路徑/data/data/[Package Name]/files/[檔名]

有時您可能會看到 /data/user/0/[Package Name] 目錄,這其實是當前 Android 帳號所存取的實際路徑。您可以把 /data/data/[Package Name] 目錄視為 /data/user/0/[Package Name] 目錄的捷徑。

寫入

                
                    public void writeFileToInternal(String fileName, String fileContents) throws IOException {
                        FileOutputStream outputStream = openFileOutput(fileName, Context.MODE_PRIVATE);
                        outputStream.write(fileContents.getBytes());
                        outputStream.close();
                    }

                    writeFileToInternal("test", "測試資料");
                
            

讀取

                
                    public String readFileFromInternal(String fileName) throws IOException {
                        File file = new File(getFilesDir(), fileName);
                        FileInputStream inputStream = new FileInputStream(file);
                        BufferedInputStream bufferedStream = new BufferedInputStream(inputStream);
                        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                        for (int result = bufferedStream.read(); result != -1; result = bufferedStream.read()) {
                            outputStream.write((byte) result);
                        }

                        // 關閉串流
                        inputStream.close();

                        // 回傳檔案字串
                        return outputStream.toString("UTF-8");
                    }

                    readFileFromInternal("test", "測試資料");
                
            

刪除

                
                    public void removeFileFromInternal(String fileName) {
                        File file = new File(getFilesDir(), fileName);
                        file.delete();
                    }

                    removeFileFromInternal("test");
                
            

快取檔案

儲存路徑/data/data/[Package Name]/cache/[檔名]

寫入

                
                    public void writeCacheFileToInternal(String fileName, String fileContents) throws IOException {
                        // 方法ㄧ
                        File file = File.createTempFile(fileName, ".tmp", getCacheDir());

                        // 方法二
                        File file = new File(this.getCacheDir(), fileName);

                        FileOutputStream outputStream = new FileOutputStream(file);
                        outputStream.write(fileContents.getBytes());
                        outputStream.close();
                    }

                    writeCacheFileToInternal("test", "測試資料");
                
            
  • 行 3:方法ㄧ使用 File.createTempFile() 方法,會在檔名 fileName 後面添加一串隨機數字,這是用來確保檔案唯一性,後續您必須使用 file.getName() 取得檔名,並將檔名儲存起來,否則後續很難再存取此檔案了。
  • 行 6:方法二是我比較常用的方法,此方法不會加入隨機變數,可以使程式碼中的檔名與實際生成的檔案一致。

關於方法ㄧ及方法二的差異,以下舉一些例子,幫助您更了解其中的差異:

File.createTempFile("test", ".tmp")
實際檔名 test1977042155964944352.tmp
File.createTempFile("test", ".txt")
實際檔名 test1977042155964944352.txt
File.createTempFile("test", ".tmp", getCacheDir())
實際檔名 test1977042155964944352.tmp
File.createTempFile("test", ".txt", getCacheDir())
實際檔名 test1977042155964944352.txt
new File(this.getCacheDir(), "test")
實際檔名 test
new File(this.getCacheDir(), "test.tmp")
實際檔名 test.tmp
new File(this.getCacheDir(), "test.txt")
實際檔名 test.txt

讀取

                
                    public String readCacheFileFromInternal(String fileName) throws IOException {
                        File file = new File(getCacheDir(), fileName);
                        FileInputStream inputStream = new FileInputStream(file);
                        BufferedInputStream bufferedStream = new BufferedInputStream(inputStream);
                        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                        for (int result = bufferedStream.read(); result != -1; result = bufferedStream.read()) {
                            outputStream.write((byte) result);
                        }

                        // 關閉串流
                        inputStream.close();

                        // 回傳檔案字串
                        return outputStream.toString("UTF-8");
                    }

                    readCacheFileFromInternal("test", "測試資料");
                
            
  • 行 2:與永久檔案只差在 getCacheDir() 方法,永久檔案是使用 getFilesDir() 方法。

刪除

                
                    public void removeCacheFileFromInternal(String fileName) {
                        File file = new File(getCacheDir(), fileName);
                        file.delete();
                    }

                    removeCacheFileFromInternal("test");
                
            
  • 行 2:與永久檔案只差在 getCacheDir() 方法,永久檔案是使用 getFilesDir() 方法。