標籤:
在這篇教程裡,我將示範如何在iOS應用內壓縮和解壓檔案。我們會使用到一個叫做ZipArchive的第三方庫來實現這一功能。雖然還有其他壓縮和解壓檔案的方案,但我感覺ZipArchive是最快和最易使用的。
為什麼我需要解壓檔案?
這個問題很好。有很多理由可以用來解釋為什麼你的應用需要支援壓縮和解壓檔案,這是其中一些:
蘋果的50M下載限制
蘋果強制要求通過3G網路下載的應用大小不能超過50M,繞過這個限制的方法是盡量讓你的二進位包足夠小,然後在應用裡下載需要的資源,當然最好的方式是先把資源打包成一個zip檔案。完整的步驟(下邊會有示範)是:開啟App,檢測是否有資源更新、下載zip檔案、解壓zip檔案。這樣處理的話你就發行就緒容量更小的應用,然後動態擷取資源。
動態更新內容
我碰到過這個問題。當你的應用需要更新資源,通常是發布一個新的包到App Store,但這可能需要花一周時間讓蘋果審核。更快的方式是把資源打包並發布到某個伺服器(甚至是你的Dropbox),然後通過你的應用下載並解壓這些資源。通過這種方式,無論何時你想發布只修改資源的更新,都不需要向App Store發布一個新版本。
從Web下載Zip檔案
Safari和Mail一個很大的失敗之處是不能開啟zip檔案,如果能夠支援在行動裝置上查看zip文檔那會是非常棒的。很多從商店裡下載的應用都支援這個功能,你也可以用ZipArchive來實現這樣的功能。
設定你的工程
從http://code.google.com/p/ziparchive/下載一份ZipArchive的拷貝,或者你可以在終端輸入下邊這條命令擷取:
svn checkout http://ziparchive.googlecode.com/svn/trunk/ziparchive-read-only
擷取到了代碼後,從minizip目錄刪除MakeFile檔案。我們會讓Xcode編譯這些檔案。拖動minizip目錄、ZipArchive.h和ZipArchive.mm到你的工程,確保選中“Create groups for any added folders”以及“targets”。
注意:不支援ARC
如果你在項目中使用ARC,你需要告訴編譯器不要為ZipArchive使用ARC。要配置這個請點擊工程左邊的列表,然後點擊你的target並選擇“Build Phases”標籤。
展開“Compile Sources”,找到ZipArchive.mm並雙擊,在彈出的框中輸入“-fno-objc-arc”並點擊Done。
串連libz
最後一步是和libz.1.2.5.dylib串連,在Build Phases選項卡中展開Link Binary With Libraries節,並點擊“+”按鈕來添加新的庫。從列表裡找到libz.1.2.5.dylib,選中並點擊Add。
現在,編譯你的工程,應該會成功且沒有任何錯誤。有一點需要注意的是ZipArchive可能會產生一些警告,這沒什麼大不了,但是如果你有代碼潔癖(你應該有),深挖代碼,看你自己能否解決他們。
下載和解壓檔案
下邊我會展示從web下載、解壓和在項目中使用zip檔案是如何的簡單。這裡使用的下載代碼非常基礎,如果沒有更多的調試可能無法用在實際產品中。
例子工程擁有一個類似這樣的view:
這就是一個UIImageView和UILabel,在view的controller裡我為他們添加了IBOutlet,下載例子工程可以查看具體的實現。我們會從web下載一個包含了圖片和文本的zip檔案,你可以從上邊的看到他們。解壓之後,圖片會被設定到UIImageView,文本裡的內容會顯示到UILabel。
1. 應用ZipArchive標頭檔
#import "ZipArchive.h"
2. 下載zip檔案
// 1 dispatch_queue_t queue = dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);dispatch_async(queue, ^{ NSURL *url = [NSURL URLWithString:@"http://www.icodeblog.com/wp-content/uploads/2012/08/zipfile.zip"]; NSError *error = nil; // 2 NSData *data = [NSData dataWithContentsOfURL:url options:0 error:&error]; if(!error) { // 3 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); NSString *path = [paths objectAtIndex:0]; NSString *zipPath = [path stringByAppendingPathComponent:@"zipfile.zip"]; [data writeToFile:zipPath options:0 error:&error]; if(!error) { // TODO: Unzip } else { NSLog(@"Error saving file %@",error); } } else { NSLog(@"Error downloading zip file: %@", error); }});
上邊的代碼會從iCodeBlog下載zip檔案,並儲存到應用的caches目錄。步驟是:
1)建立隊列以預設的優先順序運行我們的代碼
2)從web擷取資料
3)解析出caches目錄路徑,並把下載到的資料寫入到本地
現在你已經把檔案下載到了本地磁碟,是時候解壓並使用這些檔案了。
3、解壓下載的檔案
最後一步是解壓你剛剛下載到的檔案。有一點要明確的是,zip儲存在/Library/Caches/zipfile.zip,解壓出來的內容也在這個目錄。
用下邊的代碼代替上邊代碼裡的// TODO: Unzip。
ZipArchive *za = [[ZipArchive alloc] init];// 1if ([za UnzipOpenFile: zipPath]) { // 2 BOOL ret = [za UnzipFileTo: path overWrite: YES]; if (NO == ret){} [za UnzipCloseFile]; // 3 NSString *imageFilePath = [path stringByAppendingPathComponent:@"photo.png"]; NSString *textFilePath = [path stringByAppendingPathComponent:@"text.txt"]; NSData *imageData = [NSData dataWithContentsOfFile:imageFilePath options:0 error:nil]; UIImage *img = [UIImage imageWithData:imageData]; NSString *textString = [NSString stringWithContentsOfFile:textFilePath encoding:NSASCIIStringEncoding error:nil]; // 4 dispatch_async(dispatch_get_main_queue(), ^{ self.imageView.image = img; self.label.text = textString; });
下邊解釋這段代碼是如何工作的:
1)開啟檔案,並在記憶體中解壓
2)把解壓出的記憶體寫入caches目錄
3)使用解壓出的檔案
4)用剛擷取到的資料更新UI
真的就這麼簡單。
壓縮檔
下邊你會看到如何壓縮檔。使用者需要通過web或者email分享多個檔案的時候,這顯得非常方便。如果你完成了上邊的步驟,caches目錄會有些檔案可供我們重新壓縮並發送。我會壓縮你剛剛解壓的兩個檔案,把他們填充到一個新的zip檔案中,並把新的zip檔案寫入documents目錄。
在我的例子工程中,我建立了一個叫做“Zip Files”的按鈕,它按下時會連結到一個名為zipFileButtonPressed:的IBAction,這裡我們會進行壓縮工作:
- (IBAction)zipFilesButtonPressed:(id)sender{ // 1 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *docspath = [paths objectAtIndex:0]; // 2 paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); NSString *cachePath = [paths objectAtIndex:0]; // 3 NSString *zipFile = [docspath stringByAppendingPathComponent:@"newzipfile.zip"]; // 4 ZipArchive *za = [[ZipArchive alloc] init]; [za CreateZipFile2:zipFile]; // 5 NSString *imagePath = [cachePath stringByAppendingPathComponent:@"photo.png"]; NSString *textPath = [cachePath stringByAppendingPathComponent:@"text.txt"]; // 6 [za addFileToZip:imagePath newname:@"NewPhotoName.png"]; [za addFileToZip:textPath newname:@"NewTextName.txt"]; // 7 BOOL success = [za CloseZipFile2]; NSLog(@"Zipped file with result %d",success);}
這裡是上邊代碼的工作原理:
1)解析出documents目錄的路徑,在需要寫新的zip檔案時需要這個路徑。
2)解析出caches目錄的路徑,我們需要通過它擷取需要被壓縮的檔案。
3)擷取新zip檔案的路徑。
4)建立ZipArchive類的執行個體,並告訴它在記憶體裡建立一個新的zip檔案。注意:在調用CloseZipFile2方法之前,這個新的zip檔案不會寫到磁碟上
5)擷取將要被壓縮檔的路徑
6)把要壓縮的檔案添加到ZipArchive的執行個體,你可以在這裡添加多個檔案,甚至可以添加目錄(如果你願意,你可以添加整個caches目錄)。
7)把zip檔案寫到磁碟,我輸出了結果以便確認壓縮是否成功。
運行這個應用,點擊“Zip Filse”按鈕,查看應用的documents目錄,在~/Library/Application Support/iPhone Simulator/[iOS Version]/Applications/[Unique ID]/Documents。這個目錄應該包含一個名為newzipfile.zip的壓縮檔,如果你解壓,你可以看到你壓縮的檔案。
結束語
你現在知道如何使用ZipArchive庫在iOS裝置上壓縮和解壓檔案。你可以在下邊下載例子工程。如果你有任何問題和建議,請在這篇文章後留言或者在Twitter上聯絡我@brandontreb(原作者)。
http://ju.outofmemory.cn/entry/24090
【轉】用ZipArchive在App裡壓縮、解壓檔案