Android問題之res/raw和assets的區別及檔案大小限制
*res/raw和assets的相同點:
1.兩者目錄下的檔案在打包後會原封不動的儲存在apk包中,不會被編譯成二進位制。
*res/raw和assets的不同點:
1.res/raw中的檔案會被對映到R.java檔案中,訪問的時候直接使用資源ID即R.id.filename;assets資料夾下的檔案不會被對映到R.java中,訪問的時候需要AssetManager類。
2.res/raw不可以有目錄結構,而assets則可以有目錄結構,也就是assets目錄下可以再建立資料夾
*讀取檔案資源:
1.讀取res/raw下的檔案資源,通過以下方式獲取輸入流來進行寫操作
-
InputStream is = getResources().openRawResource(R.id.filename);
2.讀取assets下的檔案資源,通過以下方式獲取輸入流來進行寫操作
- AssetManager am = null;
- am = getAssets();
- InputStream is = am.open("filename");
補充一下:在未知目錄下有哪些檔案,該去和獲取這些檔案的名稱並把檔案拷貝到目標目錄中呢?(用於內建檔案但不知道檔名稱,需要篩選出想要的檔案然後拷貝到目標目錄中,推薦內建在assets資料夾中)
1.res/raw目錄:
通過反射的方式得到R.java裡面raw內部類裡面所有的資源ID的名稱,然後通過名稱獲取資源ID的值來讀取我們想要的檔案。(這個方法我沒試過,有用過的同學麻煩發一段程式碼看看)。
2.assets目錄:
getAssets().list("");來獲取assets目錄下所有資料夾和檔案的名稱,再通過這些名稱再讀取我們想要的檔案。
Android系統對資原始檔(res/raw和assets資料夾下)的大小有限制,預設最大僅支援1M的檔案。否則apk程式將報錯。如果AssetManager或Resources classes方法來獲取InputStream,將丟擲java.io.IOException的異常如下DEBUG/asset(1123): Data exceeds UNCOMPRESS_DATA_MAX。
1、大檔案解決辦法
1.將你的資原始檔字尾改成後面aapt忽略壓縮的檔案字尾。
2.在命令列上使用-0引數來指定不需要壓縮的檔案字尾,具體配置檢視aapt幫助文件。
3.把資原始檔分割成多個小於UNCOMPRESS_DATA_MAX(1M)的檔案,然後在程式中進行組合。
2、aapt壓縮忽略檔案說明
由於aapt工具在打包apk檔案時,會對資原始檔進行壓縮以減少apk檔案大小。檢視aapt工具中的Package.cpp原始碼,發現有些檔案不會被壓縮處理:
static const char* kNoCompressExt[] = {
".jpg", ".jpeg", ".png", ".gif",
".wav", ".mp2", ".mp3", ".ogg", ".aac",
".mpg", ".mpeg", ".mid", ".midi", ".smf", ".jet",
".rtttl", ".imy", ".xmf", ".mp4", ".m4a",
".m4v", ".3gp", ".3gpp", ".3g2", ".3gpp2",
".amr", ".awb", ".wma", ".wmv"
};
實現步驟:
1.先把需要拷貝的大檔案分割成若干個大小小於1M的小檔案(事先寫個程式來分隔或者使用一些工具,我這裡直接寫了個程式),把這些小檔案放在assets資料夾中;
2.在程式啟動時我們獲取這些小檔案的檔名,當然我們得事先規定小檔案的命名方式方便我們來獲取這些檔名;
3.通過獲得的小檔名分別建立輸入流來合併成一個大檔案,並拷貝到sdcard中。
下面是解決方法中需要用到的一些程式碼,僅供參考,不妨自己寫。分割大檔案的方法:
public static void main(String[] args) throws Exception { // 大檔案放置的路徑 String path = "D:/"; // 大檔案的檔名稱 String base = "demo"; String ext = ".db"; // 以每個小檔案1024*1024位元組即1M的標準來分割 int split = 1024 * 1024; byte[] buf = new byte[1024]; int num = 1; // 建立輸入流 File inFile = new File(path + base + ext); FileInputStream fis = new FileInputStream(inFile); while (true) { // 以"demo"+num+".db"方式來命名小檔案即分割後為demo1.db,demo2.db,。。。。。。 FileOutputStream fos = new FileOutputStream(new File(path + base + num + ext)); for (int i = 0; i < split / buf.length; i++) { int read = fis.read(buf); fos.write(buf, 0, read); // 判斷大檔案讀取是否結束 if (read < buf.length) { fis.close(); fos.close(); return; } } fos.close(); num++; } }
private void mergeApkFile(Context c, ArrayList<String> partFileList, String dst) throws IOException { if (!new File(dst).exists()) { OutputStream out = new FileOutputStream(dst); byte[] buffer = new byte[1024]; InputStream in; int readLen = 0; for(int i=0;i<partFileList.size();i++){ // 獲得輸入流 in = c.getAssets().open(partFileList.get(i)); while((readLen = in.read(buffer)) != -1){ out.write(buffer, 0, readLen); } out.flush(); in.close(); } // 把所有小檔案都進行寫操作後才關閉輸出流,這樣就會合併為一個檔案了 out.close(); } }