代码之家  ›  专栏  ›  技术社区  ›  Jay

用C/C在Windows(XP/2003)上创建ZIP文件++

  •  11
  • Jay  · 技术社区  · 17 年前

    如果有人能分享一些能在WindowsXP/2003上成功创建zip文件的C代码示例,我将不胜感激。如果有人找不到可靠的文档或教程,那就太好了,因为MSDN搜索结果不多。我真的希望不必为此提供第三方lib,因为功能显然在那里,我只是不知道如何访问它。谷歌搜索没有发现任何有用的东西,只是诱人的零碎信息。这里希望社区中有人能整理出这一点,并能与子孙后代分享!

    7 回复  |  直到 17 年前
        1
  •  13
  •   Jay    17 年前

    如注释中其他地方所述,这只适用于已创建的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;
    
    }
    

    有鉴于此,我还尝试了另一张海报中提到的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");
    

    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)
    
        2
  •  7
  •   Sergey Kornilov    17 年前

    为此,我们使用XZip。它是免费的,它是C++源代码,工作很好。

    http://www.codeproject.com/KB/cpp/xzipunzip.aspx

        3
  •  5
  •   Lou Franco    6 年前

    编辑:这个答案是旧的,但我不能删除它,因为它已被接受。看到下一个了吗

    https://stackoverflow.com/a/121720/3937

    -----原始答案-----

    这里有这样做的示例代码

    http://www.eggheadcafe.com/software/aspnet/31056644/using-shfileoperation-to.aspx

    请确保您阅读了有关如何处理要完成的线程监视的内容。

    编辑:从注释中可以看出,此代码仅适用于现有的zip文件,但是@ Simon

    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);
    
        4
  •  4
  •   hndsoff8 hndsoff8    17 年前

    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)进行测试。

        5
  •  2
  •   ajb Vincent McNabb    6 年前

    http://www.example-code.com/vcpp/vcUnzip.asp 其中有一个非常简短的示例,可以使用可下载库解压缩文件。还有很多其他可用的图书馆。另一个例子可以在名为 Zip and Unzip in the MFC way 它有一个完整的gui示例。如果你想用.NET来做,那么在System.Compression下总是有类的。

    http://www.7-zip.org/sdk.html . 这包括几种语言的源代码和示例。

        6
  •  1
  •   Sparr    17 年前

    我不认为MFC或Windows标准C/C++API提供了内置zip功能的接口。

        7
  •  0
  •   EmmEff    17 年前

    如果你不想发布另一个库,你可以一直静态链接到免费的zip库。。。