在C / C ++中的Windows(XP / 2003)上创建ZIP文件
我正在寻找一种从Windows C / C ++ API中的文件夹创建ZIP文件的方法。我可以使用Shell32.Application CopyHere方法在VBScript中找到执行此操作的方法,并且找到了一个讲解如何在Calso中执行此操作的教程,但对于C API却一无所知(C ++也很好,项目已经使用MFC)。
如果有人可以共享一些可以在Windows XP / 2003上成功创建zip文件的示例C代码,我将非常感激。失败的话,因为有人可以找到可靠的文档或者教程,因为MSDN的搜索量不大。我真的希望避免为此而提供第三方库,因为功能显然已经存在,我只是不知道如何访问它。 Google搜索并没有什么用,只是诱骗了点点滴滴的信息。希望社区中的某人能够解决此问题并可以共享以供后代使用!
解决方案
我认为MFC或者Windows标准C / C ++ API不提供内置zip功能的接口。
编辑:这个答案是旧的,但是我不能删除它,因为它被接受了。见下一个
https://stackoverflow.com/a/121720/3937
----原始答案-----
这里有示例代码
[编辑:链接现在断开]
http://www.eggheadcafe.com/software/aspnet/31056644/using-shfileoperation-to.aspx
确保我们已阅读有关如何处理线程完成监视的信息。
编辑:从注释,此代码仅适用于现有的zip文件,但@Simon提供了此代码以创建一个空白的zip文件
FILE* f = fopen("path", "wb"); fwrite("\x50\x4B\x05\x06#include <windows.h> #include <shldisp.h> #include <tlhelp32.h> #include <stdio.h> int main(int argc, TCHAR* argv[]) { DWORD strlen = 0; char szFrom[] = "C:\Temp", szTo[] = "C:\Sample.zip"; HRESULT hResult; IShellDispatch *pISD; Folder *pToFolder = NULL; VARIANT vDir, vFile, vOpt; BSTR strptr1, strptr2; CoInitialize(NULL); hResult = CoCreateInstance(CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, IID_IShellDispatch, (void **)&pISD); if (SUCCEEDED(hResult) && pISD != NULL) { strlen = MultiByteToWideChar(CP_ACP, 0, szTo, -1, 0, 0); strptr1 = SysAllocStringLen(0, strlen); MultiByteToWideChar(CP_ACP, 0, szTo, -1, strptr1, strlen); VariantInit(&vDir); vDir.vt = VT_BSTR; vDir.bstrVal = strptr1; hResult = pISD->NameSpace(vDir, &pToFolder); if (SUCCEEDED(hResult)) { strlen = MultiByteToWideChar(CP_ACP, 0, szFrom, -1, 0, 0); strptr2 = SysAllocStringLen(0, strlen); MultiByteToWideChar(CP_ACP, 0, szFrom, -1, strptr2, strlen); VariantInit(&vFile); vFile.vt = VT_BSTR; vFile.bstrVal = strptr2; VariantInit(&vOpt); vOpt.vt = VT_I4; vOpt.lVal = 4; // Do not display a progress dialog box hResult = NULL; printf("Copying %s to %s ...\n", szFrom, szTo); hResult = pToFolder->CopyHere(vFile, vOpt); //NOTE: this appears to always return S_OK even on error /* * 1) Enumerate current threads in the process using Thread32First/Thread32Next * 2) Start the operation * 3) Enumerate the threads again * 4) Wait for any new threads using WaitForMultipleObjects * * Of course, if the operation creates any new threads that don't exit, then you have a problem. */ if (hResult == S_OK) { //NOTE: hard-coded for testing - be sure not to overflow the array if > 5 threads exist HANDLE hThrd[5]; HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPALL ,0); //TH32CS_SNAPMODULE, 0); DWORD NUM_THREADS = 0; if (h != INVALID_HANDLE_VALUE) { THREADENTRY32 te; te.dwSize = sizeof(te); if (Thread32First(h, &te)) { do { if (te.dwSize >= (FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(te.th32OwnerProcessID)) ) { //only enumerate threads that are called by this process and not the main thread if((te.th32OwnerProcessID == GetCurrentProcessId()) && (te.th32ThreadID != GetCurrentThreadId()) ){ //printf("Process 0x%04x Thread 0x%04x\n", te.th32OwnerProcessID, te.th32ThreadID); hThrd[NUM_THREADS] = OpenThread(THREAD_ALL_ACCESS, FALSE, te.th32ThreadID); NUM_THREADS++; } } te.dwSize = sizeof(te); } while (Thread32Next(h, &te)); } CloseHandle(h); printf("waiting for all threads to exit...\n"); //Wait for all threads to exit WaitForMultipleObjects(NUM_THREADS, hThrd , TRUE , INFINITE); //Close All handles for ( DWORD i = 0; i < NUM_THREADS ; i++ ){ CloseHandle( hThrd[i] ); } } //if invalid handle } //if CopyHere() hResult is S_OK SysFreeString(strptr2); pToFolder->Release(); } SysFreeString(strptr1); pISD->Release(); } CoUninitialize(); printf ("Press ENTER to exit\n"); getchar(); return 0; }HZIP newZip = CreateZip("C:\Sample.zip", NULL, ZIP_FILENAME); BOOL retval = AddFolderContent(newZip, "C:", "temp");if (ZipAdd(hZip, RelativePathNewFileFound, RelativePathNewFileFound, 0, ZIP_FILENAME) != ZR_OK)ZRESULT ret; TCHAR real_path[MAX_PATH] = {0}; _tcscat(real_path, AbsolutePath); _tcscat(real_path, RelativePathNewFileFound); if (ZipAdd(hZip, RelativePathNewFileFound, real_path, 0, ZIP_FILENAME) != ZR_OK)FILE* f = fopen("path", "wb"); fwrite("\x50\x4B\x05\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 22, 1, f); fclose(f);##代码####代码####代码####代码####代码####代码####代码####代码####代码####代码####代码####代码####代码##", 22, 1, f); fclose(f);
如果我们不想交付其他库,则可以始终静态链接到免费的zip库。
这个网站提供了一个快速的Google搜索工具:http://www.example-code.com/vcpp/vcUnzip.asp,其中有一个非常简短的示例,可以使用可下载的库解压缩文件。还有很多其他可用的库。另一个示例可在MFC项目中的名为Zip and Unzip的代码项目中获得,该示例具有完整的gui示例。如果要使用.NET进行操作,则System.Compression下始终存在这些类。
还有7压缩库http://www.7-zip.org/sdk.html。这包括几种语言的源代码和示例。
为此,我们使用XZip。它是免费的,作为C ++源代码提供,并且运行良好。
http://www.codeproject.com/KB/cpp/xzipunzip.aspx
如评论中其他地方所指出的那样,这仅适用于已经创建的Zip文件。压缩文件中的内容也必须不存在,否则将显示错误。这是我能够根据接受的答案创建的工作示例代码。我们需要链接到shell32.lib以及kernel32.lib(用于CreateToolhelp32Snapshot)。
##代码##我已决定尽管获得了半功能代码,也不走这条路,因为在进一步研究之后,它似乎显示了Folder :: CopyHere()方法实际上并不尊重传递给它的vOptions,这意味着我们不能强制其覆盖文件或者不向用户显示错误对话框。
有鉴于此,我也尝试了另一个海报提到的XZip库。该库可以很好地用于创建Zip存档,但是请注意,使用ZIP_FOLDER调用的ZipAdd()函数不是递归的,它仅在存档中创建一个文件夹。为了递归压缩档案,我们将需要使用AddFolderContent()函数。例如,要创建一个C:\ Sample.zip并将C:\ Temp文件夹添加到其中,请使用以下命令:
##代码##重要说明:AddFolderContent()函数不能像XZip库中所包含的那样起作用。它会递归到目录结构中,但是由于传递给ZipAdd()的路径中存在错误,因此无法将任何文件添加到zip存档中。为了使用此功能,我们需要编辑源代码并更改此行:
##代码##要以下内容:
##代码##上面的代码创建了一个空的zip文件,但由于注释状态而被破坏了,但是我能够使它工作。我在十六进制编辑器中打开了一个空zip,并注意到了一些区别。这是我的修改示例:
##代码##这对我有用。然后,我可以打开压缩文件夹。未经第三方程序(例如winzip)测试。