如何導出android內部存儲的文件(不用root)


  這段時間公司項目,涉及到數據緩存,由於需要緩沖的數據太多、太大,通過網絡請求,再緩存到本地sqlite數據庫,太費時間,消耗流量。所以准備先在本地保存一個標准版sqlite數據庫(包含數據),打包到apk文件里,以后需要的操作就是更新數據,這樣一來,請求和操作的數據就很小了。

  那么問題來了,如何把標准版的sqlite數據庫文件(db格式)從內部存儲空間里面導出,然后放到項目中assets文件夾下?

  想從內部存儲空間里拷貝東西,首先要root,手機要root,APP也要獲得root權限。這篇博客不講如何通過root拷貝內容,因為這種辦法真的很蠢,root手機會給手機帶來不可逆的改變,如果手機很貴的話,盡量不要root;即便手機root后,app也好獲得root權限,很麻煩,而且國內手機廠商rom不同,很多手機即便按照步驟一步步root了,也不能查看和賦值內部存儲空間里的文件。

  那么怎么實現呢?一個簡單到可笑的辦法(獲取這是android系統安全性上的漏洞),在代碼中,我們可以訪問、讀取內部存儲空間里的東西,也可以讀寫SD卡等外部存儲空間(要添加相應權限),那么我們就可以通過IO的方法,將內部存儲空間中的文件,拷貝到外部存儲空間,然后再從外部存儲空間里拷貝我們需要的東西就OK了。

  實現方式:

1、添加系統權限:

在AndroidManifest.xml中添加讀寫SD卡等操作權限:

    <!-- 寫入擴展存儲,向擴展卡寫入數據-->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

2、從內部存儲空間通過IO的方式拷貝到SD卡和外部存儲空間:

這個時候,已經通過網絡請求,將拿到的JSON數據寫入到sqlite數據庫中了。直接拷貝就好:

/**
     * 拷貝內部存儲空間的數據庫到外部
     *
     * @throws FileNotFoundException
     */
    public void copyDBFile() throws FileNotFoundException {
        File toDir = new File(Field.DB_PATH_SD);   //外部存儲文件夾
        if (!toDir.exists()) {
            toDir.mkdirs();
        }

        File toDb = new File(Field.DB_PATH_SD + App.BaseDB.dbName); //外部存儲數據庫
        File fromDir = new File(Field.DB_PATH + App.BaseDB.dbName); //內部存儲數據庫

        InputStream is;
        OutputStream os;
        is = new FileInputStream(fromDir);
        os = new FileOutputStream(toDb);
        byte[] buffer = new byte[1024];
        int length;
        try {
            /**
             * 拷貝過程
             */
            while ((length = is.read(buffer, 0, buffer.length)) > 0) {
                os.write(buffer, 0, length);
            }

            os.flush();
            os.close();
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

相關常量:

/**
     * 內部數據庫路徑
     */
    public static final String DB_PATH = File.separator + "data"
            + Environment.getDataDirectory().getAbsolutePath() + File.separator
            + MyApplication.getInstance().getPackageName() + File.separator + "databases" + File.separator;

    /**
     * 外部數據庫路徑
     */
    public static final String DB_PATH_SD = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "tdr" + File.separator;

 public static class BaseDB{
        public static final int version=1;
        public static final String dbName="base.db";
    }

3、在需要的地方,調用copyDBFile()

           
            try {
                //拷貝工具類通過單例獲取
                BaseDBHelper.getInstance().copyDBFile();
            } catch (FileNotFoundException e) {
                Log.e(TAG, "fileNotFount");
                Log.e(TAG, e.getMessage());
                Log.e(TAG, e.toString());
                e.printStackTrace();
            }        

執行完成以后,就可以直接在手機文件夾里看到需要的db文件了:

 

如此,就可以在非root的前提下,拷貝出內部存儲空間里的文件了。不得不說,這也許是android無意的一個安全漏洞吧!因為這個真的很蠢,就好比:一家人有一個保險櫃,里面放着家里的財產,賊要是想從保險櫃里直接拿走財物是不可以的,但是如果賊先把錢從保險櫃里拿到客廳,再從客廳拿走,就完全可以,這樣拿走,不僅沒有約束,家里主人還會主動把保險櫃密碼告訴你,把家里的大門為你敞開。。。。。。

4、后記

我之前介紹公司項目的時候,提到:我會把db文件通過離線的方式拷貝到項目的assets文件夾下,然后需要操作數據庫的時候,就操作assets文件夾里的數據庫。但是這樣做會有一個很大的性能上的問題:

sqlite數據庫的讀寫,只能讀寫/data/...中的數據庫文件,如此一來,每次讀寫或修改assets中的數據庫的時候,就要先把assets的數據庫拷貝到data對應文件夾下,然后再進行讀取,這樣一來,效率極低,並且對數據庫做完改動后,改動也沒有辦法同步到源數據庫中(也就是數據庫會自動還原)。那么這個問題該輸入解決呢?以后有時間,再整理一篇博客,說一些這個問題。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM