2011年10月4日火曜日

AndroidでZipInputStream

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

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

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

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

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

というわけで、Meshクラスのロード部分抜粋
/**
  * Assetsフォルダ内のzipファイルからMeshを作成
  * @param zipName  zip圧縮されたファイル
  * @param loader 使用するローダー
  * @return
  * @throws IOException
  */
 public static Mesh getFromAssetsZip(String zipName,MeshLoader loader) throws IOException{
  int resID = zipName.hashCode();
  //既に読み込まれている
  if (meshMap.containsKey(resID)) {
   return meshMap.get(resID);
  }
  ZipInputStream zis = new ZipInputStream(Global.view.getContext().getAssets().open(zipName));
  zis.getNextEntry(); //これやらないと、ファイルが読み込めないよ。 1zipに複数ファイル入れないでね。
  Mesh newMesh = loader.load(zis);
  meshMap.put(resID, newMesh);
  return newMesh;
 }
 /**
  * リソースに登録されたzipからMeshを作成
  * @param resID  リソースID
  * @param loader 使用するローダー
  * @return
  * @throws IOException
  */
 public static Mesh getResZip(int resID,MeshLoader loader) throws IOException{
  //既に読み込まれている
  if (meshMap.containsKey(resID)) {
   return meshMap.get(resID);
  }
  ZipInputStream zis = new ZipInputStream(Global.view.getResources().openRawResource(resID));
  zis.getNextEntry(); //これやらないと、ファイルが読み込めないよ。 1zipに複数ファイル入れないでね。
  Mesh newMesh = loader.load(zis);
  meshMap.put(resID, newMesh);
  return newMesh;
 }

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

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

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