在Windows下C++实现UNIX中的GZ格式的解压缩(附工具)
今天在做項目中遇到一個問題,項目中需要開發一個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
希望對大家有所幫助!
總結
以上是生活随笔為你收集整理的在Windows下C++实现UNIX中的GZ格式的解压缩(附工具)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 企业微信的corpsecret在哪里?
- 下一篇: 使用 Hexo + Next 搭建静态博