在Windows下C++实现UNIX中的GZ格式的解压缩(附工具)
今天在做项目中遇到一个问题,项目中需要开发一个PC工具(要求是Windows),其中需要将一些文件打包成gz文件,gz文件是UNIX系统中的压缩文件,后来找了找网上的资源,只有解压的C++源码,没有告诉你如何进行GZ格式的压缩,当然了,你还可以使用7Z软件对文件进行GZ解压缩。而本篇文章将用另外一个思路去实现GZ格式的解压缩。
首先,创建一个C++的工程项目,这里使用MFC窗体项目。
功能很简单,先看下整个窗体设计:
上面一排通过“选择文件”在下面的列表中显示文件路径,然后通过“压缩”按钮,保存到指定的目录中。
下面一排通过”选择文件”选择gz格式的压缩包,然后通过“解压”按钮,保存到指定的目录中。、
界面的功能就是这样,下面我来介绍下一些主要核心的功能。
首先,来看GZ的一个处理类:
GZHelper.h 头文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | //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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | 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可以移动指针到下一个参数中,从而遍历可变参数的值。
另外,我在工具中添加了一个目录选择的类:
头文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | //目录选择类 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文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | /* 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 */ |
如何调用:
1 2 3 4 5 6 7 8 | CFolderDialog folderDialog( "压缩到目录:" ); int result = folderDialog.DoModal( this ->m_hWnd); if (result == 1) { ... } |
最后附上该工具的源代码(内含tar命令包):GZCompressDemo.rar
希望对大家有所帮助!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫