2012年12月08日

Androidのjava.util.zipパッケージと戦った記憶

この記事はAdvent Calendar 2012 Javaの8日目だよ。

前の日の記事はryu22e(@ryu22)さんで、
Javaのデータベースマイグレーションツール「Flyway」 #JJUG』だったね。
次の日の記事はHideki Kishida(@quicy)さんがやってくれるみたいだよ。

で、この記事では、わたしが最近作っている『コミみみ』って言うAndroidアプリの動きを確認していたときのことを淡々と書くのだ。
読みやすさは全く考えられていないので覚悟して読んでね。

コミみみ』って言うのは、コミックマーケット用のアプリ……まぁ、えっと、カタログViewerなんだけど、
サークルカット(画像)をZIPで1つのファイルにまとめたものを読み込んでいるんだ。
その読み込みをするときに問題が起こったの。

ZIPファイルをJavaで扱う定番は、java.util.zipパッケージのZipFileクラスだよね。
で、ZipFileクラスで有名な問題といえば、
開こうとしているZIPファイルに含まれているファイル数が65535個を超えていると開けないってこと。
ZIP64っていう拡張仕様までサポートしてないよってことだから、不具合と言うより仕様かな。
これはAndroidに限らずある問題だね。Java7ではサポートしたみたいだけど、AndroidはJava6までだし。

65535個って言うのは、unsigned short型(2バイト)での表現の限界から来ているみたい。
だから、ZIP64をサポートしないと、それより多いファイルを含むZIPファイルは開けない。

Androidでわたしがぶつかった問題も、この『含まれているファイルの数』によるものなの。
この問題をぐーぐるさんで検索すると『多すぎるからだよ!』って言うのがたくさんヒットするよ。

でも、カタログでサークルカットが多いって言っても、35000個くらいしかないんだよね……。
65535個を超えてなくても開けないっ。
試して見ると、だいたい32000個を超えてきたくらいで開けなくなるんだよね。

はい、これでわかっちゃうと思うけど、32767個を超えると開けなくなるみたい。
Javaにはunsignedな型はないから、
unsigned shortで表現されている『含まれているファイルの数』を持つためにはint型が必要になるんだよね。
short型は-32768〜32767までしか表現できないから。
たぶん、short型でファイルの数を持っちゃっておかしくなっているんだと思う。

あれ?でも、ちょっと待って。なんでこんな問題があるの?
java.util.zipパッケージなんて大昔からあるわけでしょ?
そこに、こんな問題があるなんておかしいでしょ!

で、調べてみるとAndorid 2.3.3系では発生しないんだよね。これ。
でも、Android 4.0.xでは発生するの。Android 3.xはどっちかな〜?まぁ、どっちでもいいよね。
つまり、これ、最近……でもないかもだけど、java.util.zipパッケージが書き換えられたことで起こっているみたい。

……え?やっぱり、おかしくない?
拡張仕様をサポートしたわけでもないのに、ZipFileの実装が書き換わってる……?

Android 2.3.3系は……大丈夫っ。でも、その後書き換えられておかしくなっている……。

もしかして、OracleとGoogleの訴訟の問題から来てたりするのかな?
やっぱりGoogle、やっちゃってたのかな?とか想像してみちゃった。
詳しいこと何も知らないけどね!

Android 4系のアプリサポートはこれからだろうから、
ZIPでファイルをいっぱい使うする人は気をつけようね。

そこ!ZIPファイルで数万もファイル扱うことなんて無いなんて言わないでっ!
あ、忘れるところだった。解決方法だけど、
  1. ZIPフォーマットは簡単だから自分で作る。
  2. Android 2.3.3系は動くからそっちから持ってくる。
  3. org.apache.tools.zipパッケージを使う。
って言う感じかな。最後のは、java.util.zipパッケージより20倍〜40倍遅いからやめた方が良いと思うけど。
posted by すふぃあ at 11:34| Comment(2) | TrackBack(0) | 雁字