windows下解压tar.gz文件
最近做的一個項目,使用小工具代替人工提交到網站并獲取結果。
在開發過程中碰到了一個問題。
網站返回的格式為tar.gz文件。第一個想到的方式是直接用第三方工具,使用的是7z。但用戶那里使用的系統為win10,不以管理員身份運行會沒有調用第三方工具的權限。遂決定用庫解決該問題。
這里記錄下windows下解壓tar.gz的一些問題。
其實tar.gz是兩次封裝。
第一次是tar打包(這里不會壓縮,文件反而會更大),第二次是gz文件的算法壓縮。
解壓GZ文件使用的是zlib庫。
這里說一下zlib的使用過程。
一開始我是圖懶直接從官網下載的windows develop版本,包含頭文件,靜態庫和dll。但運行過程中出現了缺少zlib1.dll的問題。經過反復的折騰,沒有解決。他這個庫生成時間是2005年,可能在新版windows下運行會有問題把。
本人對系統了解還是不多,沒有找到深層次的原因。如果有大神知道原理請告知。
在此之后下載了新版并進行編譯。具體編譯過程忘記了,挺順利的。在vs命令行里執行一條命令后,會直接生成vs工程項目。選擇靜態庫或動態庫編譯即可。
不知道這里能不能發csdn的連接,我是根據這篇文章來編譯的:http://blog.csdn.net/shellching/article/details/8116622。
當然我用的版本是vs2015。用這種方法也能順利通過。
接下來就是解壓了。一開始我從網上找到的資料全是compress和uncompress,后來發現:
錯啦!
壓根就不是這么解壓的。
具體原因沒有詳細了解到,大體上我的理解就是,其實gz文件需要一個頭來標識壓縮級別等信息。而compress和uncompress只是壓縮字節流,單純地調用uncompress而不知道數據的開始位置和數據的壓縮信息的話,是無法正常壓縮的。
下面是解壓代碼:
//初始化結構體
z_stream strm = { 0 };
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
//下面分別初始化源數據,源數據長度,目標數據長度和目標數據地址
strm.next_in = srcBuffer;
strm.avail_in = srcLength;
strm.avail_out = dstLength;
strm.next_out = dstBuffer;
//下面函數的第二個參數在頭文件的函數說明里有,這里的這個參數意思是自動判斷信息頭
int res = inflateInit2(&strm, MAX_WBITS + 32);
//執行解壓縮
res = inflate(&strm, Z_NO_FLUSH);
//回收資源
inflateEnd(&strm);
上面的代碼我去掉了結果判斷的部分,具體的結果判斷大家參考頭文件的信息把。我其實在代碼里沒有進行詳細判斷,只是簡單判斷了成功失敗,并沒有返回原因。這里就不貼上來坑大家了。
有幾點注意事項:
1,目標內存長度需要足夠。當然不夠也沒關系,該函數會在執行時發現并返回這個錯誤,在判斷后逐步增加緩沖區即可。
2,轉換成功后目標數據的長度為:dstLen -strm.avail_out。
3,如果你編譯后使用這些函數,這個程序會莫名其妙地崩掉。
4,如果你是新手(現在沒啥新手在VS上用這個了把。。。),可能會報無法連接的錯誤,當然你引入了lib還是會報。
先說下為何會報連接錯誤,需要加一個宏ZLIB_WINAPI,如果有新手在看的話,跟大家分享下。
一個庫,無論是靜態還是動態。在有頭文件的時候,有兩個地方需要注意,一是你編譯庫的時候,導出函數前面有沒有加export,第二個是你引入庫的時候,導出函數前面是不是import。
有些庫因為要處理跨平臺的問題,庫的源碼的宏定義會非常復雜,這時候要仔細觀察,設置響應的宏確定庫函數的正確引入和導出,如果你用VS的話,VS會根據宏定義的狀態來高亮具體代碼用到哪個宏。
在編譯和引入的時候都要注意。
接下來,在崩潰之后,各種google原因,但始終沒有發現是為什么,因為當時沒有解壓成功,我也一度懷疑自己的代碼有問題,或者庫有問題。
在這里,感謝一位大神:http://blog.csdn.net/u013283835/article/details/70311499
真是跪謝。這是怎么發現的。祝您能修到孫藝珍。
根據這位大神的說法,把預處理器中的ASMINF這個宏去掉。執行程序將轉換出來的字節流寫入文件。搞定了。
這里鄙視下CSDN:本人的csdn因為前幾年給別人發QSS代碼被封了。我也是醉了,發個QSS代碼都能封。就這還搞技術論壇。呵呵。
接下來就進行tar文件的解析了。最開始想到的使用libarchive庫。
嗯。編譯,連接,導入,使用。在經歷過種種挫折后,我突然發現:libarchive不支持全路徑,只能打開當前工作目錄下的文件,當然也可能是我某個配置沒有配好,但libarchive的資料實在是太少了。
官方文檔也只有很粗略的解釋。而且在win10下,如果程序安裝在C盤program files下,運行程序是沒有創建文件權限的,在其他盤則需要不停設置當前路徑。放棄。這個庫真不是一般的難用。
查了下tar文件的格式:
http://blog.chinaunix.net/uid-20357359-id-1963469.html
https://www.gnu.org/software/tar/manual/html_node/Standard.html
嗯,貌似做簡單的拆包不復雜嗎。外加我做的小項目中tar文件本就是自動生成的,只有一級目錄。自己解決把。
下面是代碼:
typedef structposix_header
{
char name[100];
char mode[8];
char uid[8];
char gid[8];
char size[12];
char mtime[12];
char chksum[8];
char typeflag;
char linkname[100];
char magic[6];
char version[2];
char uname[32];
char gname[32];
char devmajor[8];
char devminor[8];
char prefix[155];
}TAR_HEADER;
//參數為目標路徑、tar緩沖區,緩沖區長度
void ExtractTar(const char *dstDir, BYTE *buffer, uLongf len) { uLongf index = 0; while (true) { if (index == len - 1) { return; } TAR_HEADER newHeader = { 0 }; memcpy(&newHeader, buffer + index, sizeof(TAR_HEADER)); index += sizeof(TAR_HEADER); if (strcmp(newHeader.name, "") == 0) { return; } char fileFullPath[MAX_PATH] = { 0 }; memcpy(fileFullPath, dstDir, strlen(dstDir)); memcpy(fileFullPath + strlen(dstDir), newHeader.name, strlen(newHeader.name)); FILE *newFile = NULL; fopen_s(&newFile, fileFullPath, "wb+");long size = strtol(newHeader.size, (char **)(&(newHeader.size) + 12), 8); size_t res = fwrite(buffer + index, 1, size, newFile); fclose(newFile); index += size;
//填充字節塊 int nblock = index / 512 + 1; index = nblock * 512; } }
注意:
1,我還是去掉了返回判斷的代碼,如果想完成健壯代碼請判斷各種狀態返回值。
2,這段代碼不能解壓包含文件夾或者多級目錄的tar文件,也不能解壓特殊文件,也沒有判斷字節偏移等數據。
簡單來說,這段代碼只能保證我這個小項目的需求。而且很大程度上滿足不了其他需求。
經過上面兩步,基本上滿足了我的需求。在這里分享給大家。
總結
以上是生活随笔為你收集整理的windows下解压tar.gz文件的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 企业微信开发基本步骤
- 下一篇: 多智能体系统(MAS)简介