2008-09-23 34 views
11

Tôi đang tìm cách tạo tệp ZIP từ một thư mục trong các API Windows C/C++. Tôi có thể tìm cách để làm điều này trong VBScript bằng cách sử dụng phương pháp Copy32.Application CopyHere, và tôi tìm thấy một hướng dẫn giải thích làm thế nào để làm điều đó trong C# cũng, nhưng không có gì cho C API (C + + là tốt quá, dự án đã sử dụng MFC).Tạo một tệp ZIP trên Windows (XP/2003) trong C/C++

Tôi thực sự biết ơn nếu có ai có thể chia sẻ một số mã mẫu C có thể tạo thành công tệp zip trên Windows XP/2003. Không có điều đó, nếu ai đó có thể tìm thấy tài liệu vững chắc hoặc một hướng dẫn sẽ là tuyệt vời, kể từ khi tìm kiếm MSDN không bật lên nhiều. Tôi thực sự hy vọng để tránh phải gửi một lib bên thứ ba cho điều này, bởi vì chức năng rõ ràng là có, tôi chỉ không thể tìm ra cách để truy cập nó. Google tìm kiếm không có gì hữu ích, chỉ cần trêu ngươi bit và mẩu thông tin. Đây là hy vọng một người nào đó trong cộng đồng đã sắp xếp điều này và có thể chia sẻ nó cho hậu thế!

+1

Cách tạo thư mục nén trong Windows bằng Win32 API: http://ixmx.wordpress.com/2009/09/16/how-to-create-a-compress-folder-in-windows-using-win32 -api/ – anno

+0

Bạn có thể sử dụng Shell32.CopyHere từ C hoặc C++, chỉ cần gọi các API win32 cần thiết để khởi tạo đối tượng COM. – Motes

Trả lời

4

EDIT: Câu trả lời này là cũ, nhưng tôi không thể xóa nó vì nó đã được chấp nhận. Xem tiếp theo một

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

----- XỨ ĐÁP -----

Có mẫu mã để làm điều đó ở đây

[EDIT: Link hiện đang bị phá vỡ]

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

Đảm bảo bạn đọc về cách xử lý giám sát cho chuỗi hoàn tất.

Edit: Từ các ý kiến, mã này chỉ hoạt động trên file zip hiện có, nhưng @Simon cung cấp mã này để tạo ra một tập tin zip trống

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); 
+0

Tôi đã tìm thấy mã mẫu trước đó, nhưng nó không thực sự xuất hiện để làm việc như là. Cuối cùng tôi đã có được nó để biên dịch và chạy sau khi một số tinh chỉnh và nó sắp xếp các công trình, miễn là tệp ZIP đã tồn tại. Nếu không có ai khác đưa ra một câu trả lời hoàn chỉnh hơn, tôi sẽ chấp nhận câu trả lời này. – Jay

+1

Tạo zip trống với: FILE * f = fopen ("đường dẫn", "wb"); fwrite ("\ x80 \ x75 \ 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); –

+1

Mã được cung cấp để tạo tệp zip trống không tạo tệp hợp lệ (không thể mở bằng bất kỳ phần mềm zip nào bao gồm winzip, ZIP tích hợp sẵn Windows, BOMArchiver trên OS X hoặc giải nén trên dòng lệnh. – Jay

1

Tôi không nghĩ rằng các API C/C++ tiêu chuẩn của MFC hoặc Windows cung cấp giao diện cho chức năng zip tích hợp sẵn.

0

Bạn luôn có thể tĩnh liên kết đến các thư viện zip phần mềm miễn phí nếu bạn không muốn chuyển một thư viện khác ...

2

Tìm kiếm nhanh trên Google đã đưa ra trang web này: http://www.example-code.com/vcpp/vcUnzip.asp có một ví dụ rất ngắn để giải nén tệp bằng thư viện có thể tải xuống. Có rất nhiều thư viện khác có sẵn. Một ví dụ khác là availaible trên Code Project có tiêu đề Zip and Unzip in the MFC way có toàn bộ ví dụ gui. Nếu bạn muốn làm điều đó với .NET thì luôn luôn có các lớp dưới System.Compression.

Ngoài ra còn có thanh công cụ 7-Zip http://www.7-zip.org/sdk.html. Điều này bao gồm nguồn cho nhiều ngôn ngữ và ví dụ.

13

Như đã đề cập ở những nơi khác trong các ý kiến, điều này chỉ sẽ làm việc trên một tập tin Zip đã tạo. Nội dung cũng phải không tồn tại trong tệp zip hoặc lỗi sẽ được hiển thị. Đây là mã mẫu làm việc mà tôi có thể tạo dựa trên câu trả lời được chấp nhận. Bạn cần liên kết đến shell32.lib và cũng là kernel32.lib (cho 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; 

} 

tôi đã quyết định không đi tuyến đường này mặc dù nhận được mã bán chức năng, kể từ sau khi tiếp tục điều tra, nó xuất hiện Folder :: phương pháp CopyHere() không thực sự tôn trọng vOptions truyền cho nó, có nghĩa là bạn không thể ép buộc ghi đè lên các tệp hoặc không hiển thị hộp thoại lỗi cho người dùng.

Do đó, tôi đã thử thư viện XZip được đề cập bởi một người đăng khác. Thư viện này hoạt động tốt để tạo một kho lưu trữ Zip, nhưng lưu ý rằng hàm ZipAdd() được gọi với ZIP_FOLDER không đệ quy - nó chỉ tạo một thư mục trong kho lưu trữ. Để đệ quy nén một kho lưu trữ, bạn sẽ cần sử dụng hàm AddFolderContent(). Ví dụ, để tạo một C: \ Sample.zip và Thêm thư mục C: \ Temp đến nó, sử dụng như sau:

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

Lưu ý quan trọng: các AddFolderContent() chức năng không phải là chức năng như bao gồm trong XZip thư viện. Nó sẽ recurse vào cấu trúc thư mục nhưng không thêm bất kỳ tập tin vào kho lưu trữ zip, do một lỗi trong đường dẫn được chuyển đến ZipAdd(). Để sử dụng chức năng này, bạn sẽ cần phải chỉnh sửa mã nguồn và thay đổi dòng này:

if (ZipAdd(hZip, RelativePathNewFileFound, RelativePathNewFileFound, 0, ZIP_FILENAME) != ZR_OK) 

Để sau:

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) 
+0

Không có cách nào thông minh hơn để phát hiện một vỏ đang hoạt động? [h ttps: //msdn.microsoft.com/en-us//library/windows/desktop/gg537733 (v = vs.85) .aspx] (IShellDispatch.Windows) để kiểm tra các cửa sổ trình bao mở trong khoảng thời gian tự định nghĩa f.e.? – Youka

+0

Mã này hoạt động nhưng chức năng chờ đợi 'WaitForMultipleObjects' vô cùng nếu một sợi đã hoàn thành trước dòng này. Theo tài liệu msdn => [WaitForMultipleObjects] (https://msdn.microsoft.com/en-us/library/windows/desktop/ms687025 (v = vs.85) .aspx) Nó nói 'Nếu một trong các chốt này được đóng trong khi chờ đợi vẫn đang chờ xử lý, hành vi của hàm là không xác định.' Để tránh điều này, các chốt phải chỉ có cờ phải truy cập SYNCHRONIZE. Vì vậy, thay thế 'THREAD_ALL_ACCESS' trong' OpenThread (THREAD_ALL_ACCESS, FALSE, te.th32ThreadID); 'by' SYNCHRONIZE' và nó hoạt động tốt! –

3

Đoạn mã trên để tạo ra một tập tin zip có sản phẩm nào bị hỏng, như trạng thái nhận xét, nhưng tôi có thể làm cho nó hoạt động. Tôi đã mở một zip trống trong một trình soạn thảo hex, và lưu ý một vài sự khác biệt. Dưới đây là ví dụ đã sửa đổi của tôi:

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); 

Điều này phù hợp với tôi. Tôi đã có thể mở thư mục nén. Không được thử nghiệm với các ứng dụng của bên thứ 3 như winzip.

+0

Tốt, nó hoạt động. cảm ơn –

Các vấn đề liên quan