Создание zip-файла в Windows (XP/2003) в C/C++

Идея заключается в том, что для соображений скорости и кеширования операнды должны считываться с адресов, соответствующих их естественному размеру. Чтобы это произошло, элементы структуры компоновщика компилируются так, чтобы следующий член или следующая структура были выровнены.

struct pixel {
    unsigned char red;   // 0
    unsigned char green; // 1
    unsigned int alpha;  // 4 (gotta skip to an aligned offset)
    unsigned char blue;  // 8 (then skip 9 10 11)
};

// next offset: 12

Архитектура x86 всегда могла извлекать неверные адреса. Тем не менее, он медленнее, и когда несоосность перекрывает две разные строки кэша, тогда он вытесняет две строки кэша, когда выровненный доступ будет вытеснять только один.

Некоторым архитектурам на самом деле приходится ловить ложные недочетые чтения и записи и ранние версии архитектуры ARM (той, которая развивалась во всех современных мобильных процессорах) ... ну, на самом деле они просто вернули для них плохие данные. (Они проигнорировали младшие разряды.)

Наконец, обратите внимание, что строки кэша могут быть сколь угодно большими, и компилятор не пытается угадать их или сделать компромисс между пространством и скоростью. Вместо этого решения выравнивания являются частью ABI и представляют собой минимальное выравнивание, которое в конечном итоге равномерно заполняет линию кэша.

Значения TL; DR: важны.

11
задан Jay 23 September 2008 в 01:05
поделиться

7 ответов

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

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

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

Пример кода для этого есть здесь

[EDIT: Link is now broken]

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

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

Edit: Судя по комментариям, этот код работает только с существующим 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);
5
ответ дан 3 December 2019 в 02:31
поделиться

Мы используем XZip с этой целью. Это свободно, стал исходным кодом C++ и работами приятно.

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

7
ответ дан 3 December 2019 в 02:31
поделиться

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

0
ответ дан 3 December 2019 в 02:31
поделиться

Быстрый поиск Google придумал этот сайт: http://www.example-code.com/vcpp/vcUnzip.asp, который имеет очень короткий пример для разархивации файла, пользующегося загружаемой библиотекой. Существует много других доступных библиотек. Другим примером является availaible на Проекте Кода под названием Zip, и Разархивируйте в MFC путь, который имеет весь gui пример. Если Вы хотите сделать это с.NET затем под Системой всегда существуют классы. Сжатие.

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

2
ответ дан 3 December 2019 в 02:31
поделиться

Вышеупомянутый код для создания пустого zip-файла взломан, как комментарии указывают, но я смог заставить его работать. Я открыл пустую zip в Hex-редакторе и отметил несколько различий. Вот мой измененный пример:

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.

4
ответ дан 3 December 2019 в 02:31
поделиться

Как отмечено в другом месте в комментариях, это будет только работать над уже созданным 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;

}

Я решил не пойти этим путем несмотря на получение полуфункционального кода, так как после дальнейшего расследования, это появляется Папка:: CopyHere () метод на самом деле не уважает vOptions, переданный ему, что означает, что Вы не можете вынудить его перезаписать файлы или не ошибочные диалоговые окна дисплея пользователю.

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

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)
13
ответ дан 3 December 2019 в 02:31
поделиться

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

1
ответ дан 3 December 2019 в 02:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: