ZIP文件是一種很常見的壓縮文件格式,用戶在windows下經常要使用WINZIP程序進行文件壓縮和解壓操作。不過,WINZIP程序只能由用戶操作,而沒有提供開發方面的接口。這樣,要想在用戶的應用程序中加入文件壓縮和解壓功能,就有一定困難了。幸好,有ZLIB這個開放源代碼的壓縮和解壓庫可供開發人員使用。不過,ZLIB雖然支持文件壓縮和解壓,但只能對Linux/Unix下的GZ文件進行讀寫操作,對於Windows系統下的ZIP文件並不提供直接的支持。要解決ZLIB不能直接操作Windows ZIP文件的矛盾,就需要對Windows下ZIP文件結構進行分析,再結合ZLIB所提供的相關函數,加上一些開發技巧,自行開發相應的Winzip程序。
一、ZIP文件結構
ZIP文件基本結構如下:
{分文件頭信息+文件壓縮數據}+中心目錄+中心目錄記錄結束符
更詳細的說明如下:
每個分文件頭信息後面緊跟此文件壓縮數據。如果壓縮方式是不壓縮,就是該文件的從第1個字節一直到最後一個字節的原始字節流;如果壓縮方式是deflate,壓縮數據就是經過deflate算法壓縮過的字節流。
ZIP文件中通常有若干個分文件數據,最多可達到65535個。
文件的最後修改時間和日期按MS-DOS時間日期格式編碼。時間和日期均爲16位整數。
對於時間,16位格式分配如下:
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
小時 |
分 |
秒 |
對於日期,16位格式分配如下:
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
年-1980 |
月 |
日 |
ZIP文件使用32位CRC校驗碼檢查數據是否有誤。
ZIP文件中單個文件和ZIP文件本身字節數不能大於4G,否則會出錯。
文件名實際長度由文件名長這個字段指定,文件名中可以包含路徑,但不包含驅動器盤符(要特別注意的是,所有路徑分割符’\’都要轉換爲’/’,並且路徑中第一個字符不能是’/’)。
外部文件屬性這個字段,最低1個字節是文件的DOS屬性字節,其它字節均設爲0)。其中DOS屬性字節格式如下:
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
未用 |
未用 |
檔案 |
目錄 |
卷標 |
系統 |
隱藏 |
只讀 |
分文件頭相對位移和中心目錄初始偏移都是按字節表示的相對於ZIP文件開始位置的偏移量,用於在ZIP文件中準確定位。
中心目錄中每個文件都可以有註釋,用戶可以將需要保存的額外信息保存在該字段中。
二、ZLIB使用說明
ZLIB的作者是文件壓縮方面的專家,通過一系列複雜的算法實現了deflate這種格式的壓縮與解壓,並且爲開發人員提供了相對簡單的函數接口。
ZLIB流格式在RFC1950中有詳細的定義。對於ZLIB流,除去流中開頭的2個字節和結尾的4個字節,中間的連續字節流即經過deflate轉換的壓縮流。
ZLIB是開放源代碼的,可以從www.zlib.net上下載源代碼包,也可以下載編譯好的Windows系統下的DLL。目前最新的ZLIB版本爲1.2.3,dll文件名爲zlib1.dll,頭文件名爲zlib.h,還需要用一個zconf.h。
本程序一共使用了ZLIB提供的6個函數,其中壓縮函數3個,解壓函數3個。
壓縮要用到deflateInit、deflate、deflateEnd這3個函數,解壓要用到inflateInit,inflate,inflateEnd這3個函數。
deflateInit在壓縮開始之間調用,壓縮結束後調用deflateEnd;同樣,解壓之前調用inflateInit,解壓完成後調用inflateEnd。這4個函數都很好理解。
關鍵函數是deflate進行壓縮,inflate進行解壓。
deflate函數有兩個參數,stream和flush。stream是一個結構體變量,有next_in、avail_in、next_out、avail_out這四個變量。next_in表示當前輸入的字節數組,avail_in表示當前可用的輸入字節數;next_out表示當前輸出的字節數組,avail_out表示當前可用的輸出字節數。當輸入數據沒有結束時flush設爲Z_NO_FLUSH,否則設爲Z_FINISH。next_out要至少比next_in大0.0015%。
inflate函數參數和deflate相同,但flush總是設爲Z_NO_FLUSH。
爲壓縮整個文件,應當循環調用deflate函數進行數據壓縮。同樣,也要循環調用inflate函數進行解壓。當avail_out這個變量爲0時,表示輸出緩衝已滿,這時需要將next_out中數據寫入文件,寫入字節數由next_out大小-avail_out決定。然後重新調用deflate進行壓縮或inflate進行解壓。
三、程序開發過程
本程序使用Visual C++ 6.0開發。使用MFC AppWizard生成基於對話框的應用程序框架。
主對話框截圖如圖1所示。
圖1 主界面
主對話框中加入菜單,包括文件和動作兩個子菜單,其中文件菜單中只有一個打開菜單項,用於打開ZIP文件。動作菜單有加入、刪除、解出三個菜單項。
菜單下面是一個MSFlexGrid控件,用於顯示ZIP文件中的文件。
主對話框底部有三個標籤,用於顯示有關信息。
用戶單擊文件菜單的打開命令,會出現打開文件對話框,用於打開或新建ZIP文件。
用戶單擊動作菜單中的加入命令,會出現選擇文件對話框,由用戶選擇要加入的文件。
選擇文件對話框截圖如2所示。
圖2選擇文件對話框
該對話框中,壓縮和保存路徑兩個複選按鈕默認都是選中狀態,即進行壓縮和保存文件路徑,用戶可以改變這個設置。壓縮複選按鈕左邊是一個下拉列表框,由用戶選擇驅動器,上面的MSFlexGrid列表用於顯示當前目錄和文件,用戶在該列表按空格鍵選擇文件,選中文件將出現在對話框下面的列表框中,單擊確定按鈕則進行將選擇文件加入ZIP文件。
用戶單擊動作菜單的解壓按鈕,會出現解壓對話框,由用戶輸入解壓路徑。
解出對話框截圖如下:
用戶只要輸入一個解壓目錄,並單擊確定按鈕,就會將ZIP文件中文件解壓至該目錄。
源文件中,有4個包含開發時加入的源代碼:winzip.cpp中定義一些全局變量;selectfiledlg.cpp爲選擇文件對話框類;extractdlg.cpp爲輸入解壓路徑對話框類;winzipdlg.cpp爲主對話框類,其中包含主要的源代碼;其它文件均由MFC自動生成。2