2011年10月4日火曜日

AndroidでZipInputStream

最近、ColladaをAndroidで表示しようとか頑張ってたんですが(すでに過去形)

Metaseqoiaしかり、Colladaしかり、バイナリじゃなくて、テキストファイルなんですね。

なので、読みやすいという利点はあるんですが、逆に容量が増えがち(アニメーション入れると平気で2~3Mにはなる)
Androidには何気にファイル容量制限があって、機種によっては1Mを超えたくらいでオープンできなくなるし(経験則なので、実際のところは不明)

なので、荒業で「Zip圧縮したファイルを展開しながら読む」って事ができないかなーーと。

JavaにはもともとZipInputStreamという素敵なストリームクラスがあるので、リソース読むにもAssetsから直接読むにも、ZipInputStreamを挟むだけ。

というわけで、Meshクラスのロード部分抜粋
  1. /** 
  2.   * Assetsフォルダ内のzipファイルからMeshを作成 
  3.   * @param zipName  zip圧縮されたファイル 
  4.   * @param loader 使用するローダー 
  5.   * @return 
  6.   * @throws IOException 
  7.   */  
  8.  public static Mesh getFromAssetsZip(String zipName,MeshLoader loader) throws IOException{  
  9.   int resID = zipName.hashCode();  
  10.   //既に読み込まれている  
  11.   if (meshMap.containsKey(resID)) {  
  12.    return meshMap.get(resID);  
  13.   }  
  14.   ZipInputStream zis = new ZipInputStream(Global.view.getContext().getAssets().open(zipName));  
  15.   zis.getNextEntry(); //これやらないと、ファイルが読み込めないよ。 1zipに複数ファイル入れないでね。  
  16.   Mesh newMesh = loader.load(zis);  
  17.   meshMap.put(resID, newMesh);  
  18.   return newMesh;  
  19.  }  
  20.  /** 
  21.   * リソースに登録されたzipからMeshを作成 
  22.   * @param resID  リソースID 
  23.   * @param loader 使用するローダー 
  24.   * @return 
  25.   * @throws IOException 
  26.   */  
  27.  public static Mesh getResZip(int resID,MeshLoader loader) throws IOException{  
  28.   //既に読み込まれている  
  29.   if (meshMap.containsKey(resID)) {  
  30.    return meshMap.get(resID);  
  31.   }  
  32.   ZipInputStream zis = new ZipInputStream(Global.view.getResources().openRawResource(resID));  
  33.   zis.getNextEntry(); //これやらないと、ファイルが読み込めないよ。 1zipに複数ファイル入れないでね。  
  34.   Mesh newMesh = loader.load(zis);  
  35.   meshMap.put(resID, newMesh);  
  36.   return newMesh;  
  37.  }  

気をつけるのは getNextEntry(); をやってあげないと、zip内が1ファイルだとしても読み込み準備ができないということ。
ちなみに複数ファイルを圧縮しちゃった場合は知らんぜよ。

これによって、2MぐらいのColladaファイルも圧縮したら200kぐらいになってくれたので、今まで読めなかったファイルも読めるようになったりしました。

いや、もう、Colladaはアニメーションで挫けたので今更ではあるんですが。