在這資訊爆炸的時代中,無論是儲存檔案還是傳輸檔案,空間、流量總是相當地有限。適時地使用Zip檔案來縮減檔案大小,儼然成為應用程式開發者不可不知的技術。
以下介紹幾個比較簡單的壓縮、解壓縮方式。
使用SSZipArchive
SSZipArchive是一個第三方套件,提供了極為簡潔的壓縮、解壓縮API。 只要至SSZipArchive的github下載SSZipArchive,將SSZipArchive以及minizip兩個檔案夾加入專案中,並在專案中引入libz即可。
壓縮:
NSString *zippedFilePath = @"欲建立的zip檔檔案的絕對路徑";
//欲加入zip檔的檔案列表
NSArray *sourceFiles = [NSArray arrayWithObjects:
[[NSBundle mainBundle] pathForResource:@"檔案1" ofType:@"副檔名"],
[[NSBundle mainBundle] pathForResource:@"檔案2" ofType:@"副檔名"]
nil];
[SSZipArchive createZipFileAtPath:zippedPath withFilesAtPaths:sourceFiles];
解壓縮:
NSString *zipFilePath = @"zip檔案的絕對路徑";
NSString *destDirPath = @"解壓縮目的地資料夾的絕對路徑";
[SSZipArchive zipFilePath destDirPath];
如何?是不是一目了然呢?
然而,有些時候,我們並不想解壓縮整個zip檔,而是希望能夠只解壓縮其中一部份的檔案。
這時候就要使用另外一個第三方套件 - Objective-Zip。
使用Objective-Zip
Objective-Zip提供了較為完整的壓縮、解壓縮API,讓應用程式開發者能夠存取zip檔案中各個檔案的資訊。 只要至Objective-Zip的github下載Objective-Zip,將ARCHelper、ZLib、MiniZip、Objective-Zip四個檔案夾加入專案中即可。
(補充:由於SSZipArchive與Objective-Zip皆使用到了minizip,若同時將SSZipArchive與Objective-Zip所需的資料夾都放入同專案中編譯,需避免因重複的檔案導致編譯失敗)
壓縮:
首先,建立一個ZipFile物件。mode後的參數使用ZipFileModeCreate,表示此ZipFile物件是用來建立壓縮檔。
ZipFile *zipFile= [[ZipFile alloc] initWithFileName:@"zip檔案檔名"
mode:ZipFileModeCreate];
接著,針對每一個需要加入zip檔中的檔案,建立一個ZipWriteStream物件。
其中接在writeFileInZipWithName後的參數,表示此檔案在zip檔中的路徑。 舉例來說,如:folder1/file1.txt,則表示此ZipWriteStream物件會將檔案寫入至zip檔中的folder1資料夾內,檔名為file1.txt的檔案。
ZipWriteStream *stream= [zipFile writeFileInZipWithName:@"folder1/file1.txt"
compressionLevel:ZipCompressionLevelBest];
然後,再透過此ZipWriteStream物件的writeData方法,將欲寫入的檔案內容,以NSData形態傳入。 每寫完一個檔案後,皆需呼叫finishedWriting方法以完成寫入。
NSString* filepath = @"欲加入的來源檔案的絕對路徑";
NSData* filedata = [[NSFileManager defaultManager] contentsAtPath:filepath]
[stream writeData:filedata];
[stream finishedWriting];
當所有需要加入zip檔中的檔案皆已完成寫入時, 請務必呼叫ZipFile物件的close方法,完成建立zip檔的動作。
[zipFile close];
解壓縮:
建立一個ZipFile物件。mode後的參數使用ZipFileModeUnzip,表示此ZipFile物件是用來解壓縮檔用。 ZipFile *zipFile= [[ZipFile alloc] initWithFileName:@"zip檔案檔名" mode:ZipFileModeUnzip];
在Objective-Zip中,使用了FileInZipInfo物件,記錄zip檔中的某一個檔案的資訊。
而ZipFile物件的listFileInZipInfos方法,可以取得zip檔案中的所有FileInZipInfo:
NSArray *infos= [unzipFile listFileInZipInfos];
for (FileInZipInfo *info in infos) {
//透過FileInZipInfo分別處理zip檔中的每一個檔案...
}
FileInZipInfo物件提供了以下幾個property存取示此檔案的相關資訊:
1. name: 此檔案在zip檔案中的路徑。
如:folder1/file1.txt,則表示此檔案在zip檔案中的folder1資料夾內,檔名為file1.txt。
2. size: 此檔案壓縮過後的大小。
3. length: 此檔案未壓縮的大小。
透過FileInZipInfo解壓縮該檔案時,需針對該檔案建立一個ZipReadStream物件。
[zipFile locateFileInZip:info.name]; //info變數是上方例子for迴圈中所取得的FileInZipInfo物件
ZipReadStream *read= [unzipFile readCurrentFileInZip];
接著,將該檔案內容以ZipReadStream物件的readDataWithBuffer方法,讀入至NSMutableData物件。再使用NSData的writeToFile方法寫入至檔案系統中即可。
NSMutableData *data= [[NSMutableData alloc] initWithLength:info.length];
int bytesRead= [read readDataWithBuffer:data];
[read finishedReading];
[data writeToFile:@"此檔案解壓縮後的絕對路徑" atomically:NO];
完成所有解壓縮的處理後,請務必呼叫ZipFile物件的close。
[zipFile close];
結語
使用zip檔案節省空間是很常見的。即使自己開發的應用程式本身不使用到zip,也可能需要能處理接受自別人的zip檔案。在iOS應用程式中存取Zip檔案並不難,也應是應用程式開發者需好好謹記在心的技術之一。
沒有留言:
張貼留言