在Windows下C++實現UNIX中的GZ格式的解壓縮(附工具)

來源:互聯網
上載者:User

      今天在做項目中遇到一個問題,項目中需要開發一個PC工具(要求是Windows),其中需要將一些檔案打包成gz檔案,gz檔案是UNIX系統中的壓縮檔,後來找了找網上的資源,只有解壓的C++源碼,沒有告訴你如何進行GZ格式的壓縮,當然了,你還可以使用7Z軟體對檔案進行GZ解壓縮。而本篇文章將用另外一個思路去實現GZ格式的解壓縮。

 

首先,建立一個C++的工程項目,這裡使用MFC表單項目。

 

功能很簡單,先看下整個表單設計:

 

上面一排通過“選擇檔案”在下面的列表中顯示檔案路徑,然後通過“壓縮”按鈕,儲存到指定的目錄中。

 

下面一排通過”選擇檔案”選擇gz格式的壓縮包,然後通過“解壓”按鈕,儲存到指定的目錄中。、

 

介面的功能就是這樣,下面我來介紹下一些主要核心的功能。

 

首先,來看GZ的一個處理類:

GZHelper.h 標頭檔

//GZ解壓縮類(配合tar.exe的可執行檔)class GZHelper{public:GZHelper();virtual ~GZHelper();static void Compress(char* gzFilePath, int fileNum, char* file, ...); //壓縮,(壓縮包路徑,檔案個數,可變參數的檔案清單)static void Compress(char* gzFilePath, int fileNum, char** files); //壓縮,(壓縮包路徑,檔案個數,檔案清單)static void Decompress(char* folderPath, char* gzFilePath); //解壓,(解壓目錄, 壓縮包路徑)private:static CString ConvertToUnix(CString winFile); //將Window上的路徑格式轉換為UNIX路徑格式static void FindFile(CString path, CString outPath); //遍曆目錄,並將目錄中的所有檔案移動到outPath中};

GZHelper.cpp

void GZHelper::Compress(char* gzFilePath, int fileNum, char* file, ...){va_list argptr;va_start(argptr, gzFilePath);va_arg(argptr, int);char** files;files = new char*[fileNum];for(int index = 0; index < fileNum; index++){char* file = va_arg(argptr, char*);CString str_file;str_file = file;files[index] = new char[str_file.GetLength()];memcpy(files[index], file, str_file.GetLength());files[index][str_file.GetLength()] = 0;}va_end(argptr);Compress(gzFilePath, fileNum, files);}void GZHelper::Compress(char* gzFilePath, int fileNum, char** files){CString str_gzFilePath(gzFilePath);CString folderPath = str_gzFilePath.Left(str_gzFilePath.ReverseFind('\\') + 1);CString command = "cd ";command = command + Path::StartupPath() + "tar && " + Path::GetDrive() + " && tar.exe zcPf ";CString unix_str_gzfile = ConvertToUnix(str_gzFilePath);command = command + "\"" + unix_str_gzfile + "\" ";for(int index = 0; index < fileNum; index++){char* file = files[index];CString str_file;str_file = file;CString unix_str_file = ConvertToUnix(str_file);command = command + "\"" + unix_str_file + "\" ";}//執行命令system(command);}void GZHelper::Decompress(char* folderPath, char* gzFilePath){CString str_folderPath(folderPath);CString str_gzFilePath(gzFilePath);CString command = "cd ";command = command + Path::StartupPath() + "tar && " + Path::GetDrive() + " && tar.exe zxvf ";CString unix_str_gzfile = ConvertToUnix(str_gzFilePath); command = command + "\"" + unix_str_gzfile + "\" ";system(command);CString outPath = str_folderPath + "\\demo";CreateDirectory(outPath, NULL);CString inPath = Path::StartupPath() + "tar\\cygdrive";GZHelper::FindFile(inPath, outPath);RemoveDirectory(inPath);}// 將Windows下的路徑轉換為UNIX路徑CString GZHelper::ConvertToUnix(CString winFile){CString unixFile;unixFile = winFile;unixFile.Replace("\\", "/");unixFile = "/cygdrive/" + unixFile.Mid(0, 1) + unixFile.Mid(2, unixFile.GetLength() - 2);return unixFile;}void GZHelper::FindFile(CString path, CString outPath){CString szDir = path + "\\*.*";CFileFind fileFind;BOOL result = fileFind.FindFile(szDir);while(result){result = fileFind.FindNextFile();if(fileFind.IsDots())continue;if(fileFind.IsDirectory()){GZHelper::FindFile(fileFind.GetFilePath(), outPath);}else{//移動檔案MoveFile(fileFind.GetFilePath(), outPath + "\\" + fileFind.GetFileName());}}fileFind.Close();}

通過代碼中,我們看到兩個方法Compress和Decompress,這裡就是作為最核心的函數。

實際上,原理就是通過windows上的命令提示字元cmd去調用一個tar的在Windows下編譯好的一個命令包,這個包的目錄內容如下:

實際上它是利用cygwin1.dll組件,將UNIX上的tar命令轉換到Windows平台上運行。

這個包我會在連同工具和源碼稍後在文章末尾一起奉上。

我們看到,在Compress中我們使用到"cd”命令符,這裡是需要將cmd當前的路徑設定到應用程式裡面的一個tar包的路徑上。

“&&”符號可以在單條指令中複合執行。

注意這裡的command,在字串路徑中最好需要用"\""將字串隔開,這是為了防止字串中的路徑包括空白字元

system函數執行cmd命令。

另外,我們看到ConverToUnix函數,它是用來表示將Windows下的路徑轉換為cygwin下的虛擬UNIX路徑:

這是什麼意思呢?現在我開啟一個cygwin.exe工具,執行df命令:

可以看到,每個磁碟上的路徑都已經對應了在cygwin中特定的虛擬路徑,如D: 對應 /cygdrive/d

 

ConverToUnix方法就是要將磁碟上的路徑轉換為cygwin可識別的虛擬路徑下面。

 

在tar.exe中對簡單的壓縮以及解壓的指令,具體可以參考:http://www.21andy.com/blog/20060820/389.html

 

大家也許注意到:static void Compress(char* gzFilePath, int fileNum, char* file, ...);

這種寫法很有趣,這個表示是一個可變形參的方法。後面“…”號,可以有任意個的參數表示,這樣做的目的,是為了可以對任意多個檔案進行壓縮。在方法中,通過va_list,va_start,va_arg,va_end,va_list作為一個參數的指標通過va_arg可以移動指標到下一個參數中,從而遍曆可變參數的值。

 

另外,我在工具中添加了一個目錄選擇的類:

標頭檔:

//目錄選擇類class CFolderDialog{public:CFolderDialog(LPCTSTR title, DWORD dwFlags = BIF_STATUSTEXT | BIF_USENEWUI | BIF_RETURNONLYFSDIRS);virtual ~CFolderDialog();virtual INT_PTR DoModal(HWND hwnd);CString GetPathName() const;private:BROWSEINFO browseInfo;CString m_path;};

cpp檔案:

/* CFolderDialog Begin */CFolderDialog::CFolderDialog(LPCTSTR title, DWORD dwFlags){char szDir[MAX_PATH];    ITEMIDLIST *pidl;    //        browseInfo.lpszTitle = title;    browseInfo.ulFlags = dwFlags;    }CFolderDialog::~CFolderDialog(){}INT_PTR CFolderDialog::DoModal(HWND hwnd){char szDir[MAX_PATH];ITEMIDLIST *pidl;browseInfo.pidlRoot = NULL;    browseInfo.pszDisplayName = szDir;browseInfo.hwndOwner = hwnd;browseInfo.lpfn = NULL;    browseInfo.lParam = 0;    browseInfo.iImage = 0;    pidl = SHBrowseForFolder(&browseInfo);    if(pidl == NULL)  return 2;    if(!SHGetPathFromIDList(pidl, szDir))return 2;m_path = szDir;return 1;}CString CFolderDialog::GetPathName() const{return m_path;}/* CFolderDialog End */

 

如何調用:

CFolderDialog folderDialog("壓縮到目錄:");int result = folderDialog.DoModal(this->m_hWnd);if(result == 1){    ...}

 

最後附上該工具的原始碼(內含tar命令包):GZCompressDemo.rar

 

希望對大家有所協助!

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.