ブログランキング・にほんブログ村へ


iPhone/iPad用潜水艦ゲームアプリ ソナーエコー iTunesにて公開中

2012年10月23日

Java Zipの解凍をするエントリ数でプログレス処理

JavaっつーかAndroidっつーか。
Javaはいろんなライブラリが全部組み込みであるかのようにさくっと使えてとっても便利。
Zipもその一つ。
ZipInputStreamを使うと、あっさりと解凍できちゃう。始めのころのJavaはこんなに便利じゃなかったのにそれでもinflaterとか素で使えて感動したってのに凄いな。
でも、解凍するエントリの数をあらかじめ知りたい場合はどうしよう?プログレスバーとか出したいときとか。あるよね。
そんなの
ZipInputStream in = new ZipInputStream(new BufferedInputStream(new FileInputStream( srcFile ) ) );
ZipEntry zipEntry;
int entryNum = 0;
try {
while( (zipEntry = in.getNextEntry()) != null){
entryNum++;
}
} catch (IOException e) {
}
で簡単じゃーん、そう思ったらこれがすっげー遅い。
どうもgetNextEntryが解凍を既にやっちゃってるか、それに近い処理をやっちゃうのか?

そういうときはZipFileを使うらしい。つかZipInputStreamもどうやらZipFileを使ってる上位クラスに過ぎないらしい。

File srcFile = new File( Zipファイルを置いたディレクトリ,Zipファイル名 );

ZipFile zipFile;
int entryNum = 0;
try {
zipFile = new ZipFile( srcFile );
entryNum = zipFile.size();

} catch (ZipException e) {
}


こんだけだす。処理速度は格段にあがりました。で、ついでに前処理もちょっとやっちゃおう、とか。
例えば必要なディレクトリだけ先行でmkdirしちゃおう、とか。

そしたら
ZipFile zipFile;
int entryNum = 0;
try {
zipFile = new ZipFile( srcFile );
entryNum = zipFile.size();

{
Enumeration<? extends ZipEntry> enums = zipFile.entries();

while( enums.hasMoreElements() ){
ZipEntry zipEntry = ( ZipEntry )enums.nextElement();

if( zipEntry.isDirectory() ){
String name = zipEntry.getName();

File file = new File( 展開先のベースディレクトリ, name );

if (file.exists() == false) { //ディレクトリがなければ作る
file.mkdir();
}
}
}
}
} catch (ZipException e) {
} catch (IOException e) {
}
こんな感じ。
しかる後にZipInputStream使って

// _progressDialog.setMax( entryNum ); //Android ASyncTask progressの最大値設定

ZipInputStream in = new ZipInputStream(new BufferedInputStream(new FileInputStream( srcFile ) ) );
ZipEntry zipEntry;
try {

for( int i=0;;i++ ){
if( i >= entryNum ){
break; //OK
}
// if( isCancelled() ){ //Android ASyncTaskの場合Cancel検出
// break; //Cancelされた
// }
zipEntry = in.getNextEntry();
if( zipEntry == null ){
break; //error
}
// publishProgress( i ); //Android ASyncTask progressを進める

String name = zipEntry.getName();
File file = new File( 展開先ディレクトリ, name );
if( !zipEntry.isDirectory() ){
BufferedOutputStream out = new BufferedOutputStream( new FileOutputStream( file ) );

byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
in.closeEntry();
out.close();
out = null;
}
}
} catch (IOException e) {
e.printStackTrace();
}


こんな感じ。非同期処理用に少々くどい書き方になってるけど。でもプログレス出すってことは非同期にならざるを得ないし。
posted by みこあいさ at 12:02| JAVA