使用C / C ++在Windows(XP / 2003)上创建ZIP文件
题
我正在寻找一种从Windows C / C ++ API中的文件夹创建ZIP文件的方法。我可以使用Shell32.Application CopyHere方法找到在VBScript中执行此操作的方法,我找到了一个教程,解释了如何在C#中执行此操作,但C API没有任何内容(C ++也很好,项目已经使用了MFC)。
如果有人可以分享一些可以在Windows XP / 2003上成功创建zip文件的示例C代码,我将非常感激。如果失败了,如果有人可以找到可靠的文档或教程,那将是很好的,因为MSDN搜索不会出现太多问题。我真的希望避免为此运送第三方库,因为功能显然存在,我只是无法弄清楚如何访问它。谷歌的搜索没有任何用处,只是引人入胜的信息。这里希望社区中有人对此进行整理,并为后人分享!
解决方案
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\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 22, 1, f);
fclose(f);
其他提示
正如评论中其他地方所述,这只适用于已创建的Zip文件。 zip文件中的内容也必须不存在,否则将显示错误。这是我能够根据接受的答案创建的工作示例代码。您需要链接到shell32.lib以及kernel32.lib(对于CreateToolhelp32Snapshot)。
#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;
}
我决定不使用半功能代码,因为经过进一步研究后,看来Folder :: CopyHere()方法实际上并不尊重传递给它的vOptions,这意味着你不能强迫它覆盖文件或不向用户显示错误对话框。
鉴于此,我尝试了另一张海报提到的XZip库。这个库适用于创建Zip存档,但请注意,使用ZIP_FOLDER调用的ZipAdd()函数不是递归的 - 它只是在存档中创建一个文件夹。为了递归压缩存档,您需要使用AddFolderContent()函数。例如,要创建C:\ Sample.zip并将C:\ Temp文件夹添加到其中,请使用以下命令:
HZIP newZip = CreateZip("C:\\Sample.zip", NULL, ZIP_FILENAME);
BOOL retval = AddFolderContent(newZip, "C:", "temp");
重要提示:AddFolderContent()函数不能正常运行,因为它包含在XZip库中。它将递归到目录结构中,但由于传递给ZipAdd()的路径中存在错误,因此无法将任何文件添加到zip存档中。要使用此功能,您需要编辑源并更改此行:
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)
我们将XZip用于此目的。它是免费的,来自C ++源代码并且运行良好。
创建一个空的zip文件的上述代码被破坏了,因为注释状态,但我能够让它工作。我在十六进制编辑器中打开了一个空拉链,并注意到一些差异。这是我修改过的例子:
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);
这对我有用。然后我就可以打开压缩文件夹了。未经过第三方应用测试,例如winzip。
此网站提供了一个快速的Google搜索: http://www.example -code.com/vcpp/vcUnzip.asp ,它有一个非常简短的示例,可以使用可下载的库解压缩文件。还有很多其他库可供使用。代码项目的另一个例子是 Zip and解压缩MFC方式,它有一个完整的gui示例。如果你想用.NET做,那么System.Compression下总会有类。
还有7-Zip图书馆 http://www.7-zip.org /sdk.html 。这包括几种语言的来源和示例。
我认为MFC或Windows标准C / C ++ API不提供内置zip功能的接口。
如果您不想发送其他库,则可以始终静态链接到免费软件库...