Вопрос

Я ищу способ создать ZIP-файл из папки в Windows C / C ++ API.Я могу найти способ сделать это в VBScript, используя метод Shell32.Application CopyHere, и я нашел руководство, объясняющее, как это сделать и на C #, но ничего для C API (C ++ тоже хорош, project уже использует MFC).

Я был бы очень признателен, если кто-нибудь сможет поделиться каким-нибудь примером кода на C, который может успешно создать zip-файл в Windows XP / 2003.В противном случае, если кто-то сможет найти надежные документы или учебное пособие, это было бы здорово, поскольку поисковые запросы MSDN дают мало результатов.Я действительно надеюсь избежать необходимости поставлять стороннюю библиотеку для этого, потому что функциональность, очевидно, есть, я просто не могу понять, как получить к ней доступ.Поиск в Google не дает ничего полезного, только дразнящие обрывки информации.Мы надеемся, что кто-то в сообществе разобрался в этом и сможет поделиться этим для потомков!

Это было полезно?

Решение

Редактировать:Этот ответ старый, но я не могу удалить его, потому что он был принят.Смотрите следующий

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

----- ОРИГИНАЛЬНЫЙ ОТВЕТ -----

Здесь есть пример кода для этого

[ПРАВИТЬ:Ссылка теперь разорвана]

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

Убедитесь, что вы прочитали о том, как обрабатывать мониторинг для завершения потока.

Редактировать:Судя по комментариям, этот код работает только с существующим zip-файлом, но @Саймон предоставил этот код для создания пустого 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() на самом деле не учитывает переданные ему параметры, что означает, что вы не можете заставить его перезаписывать файлы или не отображать пользователю диалоговые окна с ошибками.

В свете этого я также попробовал библиотеку XZip, упомянутую на другом плакате.Эта библиотека отлично подходит для создания Zip-архива, но обратите внимание, что функция ZipAdd(), вызываемая с помощью ZIP_FOLDER, не является рекурсивной - она просто создает папку в архиве.Чтобы рекурсивно заархивировать архив, вам нужно будет использовать функцию AddFolderContent().Например, чтобы создать C:\Sample.zip и добавить в него папку C: emp, используйте следующее:

HZIP newZip = CreateZip("C:\\Sample.zip", NULL, ZIP_FILENAME);
BOOL retval = AddFolderContent(newZip, "C:", "temp");

Важное замечание:функция AddFolderContent() неработоспособна в том виде, в каком она включена в библиотеку XZip.Он вернется к структуре каталогов, но не сможет добавить какие-либо файлы в zip-архив из-за ошибки в путях, переданных в ZipAdd().Чтобы использовать эту функцию, вам нужно отредактировать исходный код и изменить эту строку:

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 ++ и прекрасно работает.

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

Приведенный выше код для создания пустого zip-файла не работает, как указано в комментариях, но я смог заставить его работать.Я открыл пустой 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 в котором есть очень короткий пример распаковки файла с использованием загружаемой библиотеки.Существует множество других доступных библиотек.Другой пример доступен в Code Project под названием Заархивируйте и распакуйте архив способом MFC в котором есть целый пример графического интерфейса.Если вы хотите сделать это с .NET, тогда всегда есть классы в разделе System.Компрессия.

Существует также библиотека 7-Zip http://www.7-zip.org/sdk.html.Сюда входят исходные тексты для нескольких языков и примеры.

Я не думаю, что MFC или стандартные API Windows C / C ++ предоставляют интерфейс для встроенной функциональности zip.

Вы всегда можете статически ссылаться на бесплатную zip-библиотеку, если не хотите отправлять другую библиотеку...

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top