資料與檔案儲存空間總覽
如果您自己的 app 內有不希望與其他 app 共用的資料檔案,又不要這些私用檔案被編譯進二進位 apk,可將檔案存放在 assets(assets 的用途及用法請另行拜大神)。
但存放在 assets 的檔案是唯讀的,若您需要這些檔案可更新修改,又不希望分享給其他 app,或是不想公開,則需將檔案複製到裝置的內部儲存空間(從内部儲存空間訪問不需要任何權限)。
下面程式搭配了 AsyncTask 使用。
public class MainActivity extends Activity { private static final String TAG = "MainActivity"; ProgressDialog progdlg; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 檢查內部儲存空間是否已存在該檔案 File file = getBaseContext().getFileStreamPath("test.zip"); if(file.exists()) Toast.makeText(this, "檔案已存在", Toast.LENGTH_LONG).show(); else { // 檔案不存在, 執行 AsyncTask 將檔案自 assets 複製到內部儲存空間 // Toast.makeText(this, "no file", Toast.LENGTH_LONG).show(); new CopyFileTask().execute(); } // } private class CopyFileTask extends AsyncTask<Void, Void, Void> { protected void onPreExecute () { progdlg = ProgressDialog.show(MainActivity.this, "複製檔案練習", "檔案複製中...", true, true); } @Override protected Void doInBackground(Void...params) { Log.d(TAG, "CopyFileTask begin..."); AssetManager manager = getAssets(); String FILENAME = "test.zip"; try { FileOutputStream out = openFileOutput("test.zip", Context.MODE_PRIVATE); InputStream in = getAssets().open("test.zip"); byte[] buffer = new byte[1024]; int read = in.read(buffer); while (read != -1) { out.write(buffer, 0, read); read = in.read(buffer); } out.close(); in.close(); Log.d(TAG, "CopyFileTask end..."); } catch(IOException e) { e.printStackTrace(); } return null; } protected void onProgressUpdate(Void... args) {} protected void onPostExecute(Void args) { progdlg.dismiss(); } } }
檔案在裝置內的位置為
/data/data/完整 package name/files/
開啟 device monitor 看看模擬器
改接實際的裝置,發現是看不到的,第一層的 /data 就無法往下展開。
在 Acer B1-760HD(Android 5.0.1, API21),執行的結果,複製 1.01 MB (1,067,006 位元組) 的檔案雖然沒花多少時間,但 Google 仍強烈建議 檔案存取 之類的動作不要在主執行緒進行。
相關筆記 ----
AsyncTask - Thread 外的另一選擇