2017-12-12

【Android】將 assets 的檔案複製到內部儲存空間

參考資料 ----
資料與檔案儲存空間總覽


如果您自己的 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 外的另一選擇