標籤:sd卡 本地 pack 讀取 android系統 同步 檔案夾 tab 擴充
這段時間公司項目,涉及到資料緩衝,由於需要緩衝的資料太多、太大,通過網路請求,再緩衝到本地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對應檔案夾下,然後再進行讀取,這樣一來,效率極低,並且對資料庫做完改動後,改動也沒有辦法同步到來源資料庫中(也就是資料庫會自動還原)。那麼這個問題該輸入解決呢?以後有時間,再整理一篇部落格,說一些這個問題。
如何匯出android內部儲存的檔案(不用root)