iOSアプリで巨大な巨大なzipファイルを扱おうとして困ったことありませんか?
巨大なzipファイルを扱おうとすると、主に以下のような問題が発生します。
巨大なzipファイルの問題点
- サイズが大きすぎてメモリ上に展開できない
- 展開に時間が掛かる
- 展開後にストレージの容量を圧迫する
Documentディレクトリに展開するわけにもいかないし、 毎回tmpディレクトリに展開して削除するというのも考えもの。
特に画像ビューアー等では、アーカイブ内の特定のファイルだけ表示したいという場合が多く、 アーカイブを全展開するという方法はいまいちです。
そこで今回は、zipzapというライブラリを使って、zipファイル内の、特定のファイルを取り出す方法を紹介します。
zipzap
zipzapはiOS向けのzipライブラリ、 libzipのObjective-Cラッパーです。
BSD licenseなのでライセンス的にも使いやすいです。
インストール
CocoaPodsで一発インストール。簡単です。
Podfile
pod 'zipzap'
使い方
概要
zipzapは主にこんな構成になってます。
- アーカイブ自体を扱うZZArchive
- アーカイブ内のファイルを扱うZZArchiveEntry
ざっくりした使い方はこんな感じ。
- ZZArchiveを初期化
- ZZArchiveからZZArchiveEntryを取り出す。
- 取り出したZZArchiveEntryからデータを取得。
簡単ですね。
初期化
NSString *archiveFilePath = @"アーカイブファイルのパス";
ZZArchive *archive = [ZZArchive archiveWithContentsOfURL:[NSURL fileURLWithPath:archiveFilePath]];
ファイルを取り出す
とりあえず、最初のファイルを取り出してみます。
ZZArchiveEntry *entry = archive.entries[0]; NSLog(@"fileName:%@", entry.fileName);
ファイルの一覧はarchive.entriesで取得できます。 entryからファイル名も取得できるため、NSPredicateを使えば、目的のファイルのみ抽出することができます。
NSString *targetFileName = @"目的のファイル名"; NSPredicate *predicate = [NSPredicate predicateWithFormat:@"fileName like[c] '%@'", targetFileName]; NSArray *entries = [archive.entries filteredArrayUsingPredicate:predicate]; ZZArchiveEntry *entry = [entries objectAtIndex:0];
データを取得
対象のファイルが取り出せたら、あとはそれからデータを取得するだけです。
画像ファイルだった場合はこんな感じ。
NSData *data = entry.data; UIImage *image = [UIImage imageWithData:data scale:[UIScreen mainScreen].scale];
簡単ですね。
ちょっと待って。重いんだけど…
ZZArchiveEntryをpredicateでフィルタリングする場合、アーカイブ内の全ファイルをチェックするため、かなり重くなります。
取得したいファイルのファイル名が事前に分かっている場合、entryとファイル名の対応をNSDictionaryで保持しておくと高速にファイルを取得することができます。
entryDictionaryの生成
self.entryDictionary = [[NSMutableDictionary alloc] init]; for (ZZArchiveEntry *entry in self.archive.entries) { [self.entryDictionary setObject:entry forKey:entry.fileName]; }
entryDictionaryを使った取得
NSString *targetFileName = @"目的のファイル名"; ZZArchiveEntry *entry = [self.entryDictionary objectForKey:targetFileName];
まとめ
今回は、zipzapというライブラリを使って、巨大なzipファイルを展開せず、特定ファイルを取り出す方法を紹介しました。
特に画像ビューアーアプリ等では、zipファイルを展開せずに扱うメリットが大きいです。
この方法は絶賛開発中であるiTreasureMapの新バージョンで利用しており、 コード記述量も少なく、高速に動作しています。
zipzapの作者さんに敬意を払いつつ、是非ご活用下さい。