用zlib完成壓縮文件


要把幾個文件合並成一個壓縮文件,首先想到的開源庫就是zlib

1、下載zlib

官網:https://www.zlib.net/

其實使用哪個格式都可以,我這里選的是zip格式,下載之后解壓

 

2、編譯zlib庫

因為我使用的windows系統,所以去找vstudio下的內容。解壓之后在.\zlib-1.2.11\contrib\vstudio\下看到

對應不同的vc版本。選擇一個最新的版本,在vc14中找到zlibvc.sln,雙擊打開

因為我用的vs是2017版本,會提示這個問題,點取消就可以了

zlibvc項目下內容如下:

其中編譯zlibvc就可以生成zlib的lib庫和dll庫,其他project都依賴zlibvc。

minizip是zlib壓縮文件的示例,miniunz是解壓示例。

圖省事直接全部生成,但是生成失敗,報錯信息如下:

去報錯路徑找到bld_md64.bat,右鍵編輯查看內容:

ml64.exe /Flinffasx64 /c /Zi inffasx64.asm
ml64.exe /Flgvmat64 /c /Zi gvmat64.asm

 

在cmd中輸入ml64.exe,輸出

'ml64.exe' 不是內部或外部命令,也不是可運行的程序
或批處理文件。

意思是ml64.exe沒找到,用everything查找又確實能找到ml64.exe

把bat文件中的ml64.exe改成絕對路徑

"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64\ml64.exe" /Flinffasx64 /c /Zi inffasx64.asm
"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64\ml64.exe" /Flgvmat64 /c /Zi gvmat64.asm

 

為了保留案發現場把文件另存為一個新的文件,起名為bld_ml64_2.bat

回到zlibvc.sln,右鍵zlibvc,點擊屬性-生成事件-預先生成事件,編輯命令行:

cd ..\..\masmx64

bld_ml64_2.bat

保存,重新編譯,成功

 

3、學習minizip的使用過程

全部生成也可以生成minizip,這時候就可以通過debug學習minizip的使用過程了。

用到的幾個主要函數如下:

zipOpen2_64        用於創建一個新的zip文件

zipOpenNewFileInZip3_64  用於在zip文件中添加新文件
zipCloseFileInZip      關閉zip文件中的新文件
zipClose          關閉zip文件
 

4、封裝一下

根據minizip.c中的內容,可以壓縮文件,但是在自己的項目中想要添加一個封裝文件的功能還是很繁瑣,所以特意將minizip.c中的main函數封裝一下

新建一個sln,添加include路徑(zlib路徑)和鏈接器附加依賴項(編譯zlibvc生成的zlibwapi.dll,在.\zlib-1.2.11\contrib\vstudio\vc14\x64\ZlibDllDebug\目錄下)

新建FileZipper.hpp和FileZipper.cpp

FileZipper.hpp

#ifndef FILEZIPPER_HPP
#define FILEZIPPER_HPP

#include <vector>
#include <string>


#include "contrib/minizip/zip.h"
#include "contrib/minizip/iowin32.h"

#define WRITEBUFFERSIZE (16384)
#define MAXFILENAME (256)

class CFileZipper
{
public:
    CFileZipper();
    ~CFileZipper();

    int ZipFiles(std::string &zipFileName, std::vector<std::string> files, bool bAppendFile = false, int nCompressLevel = 0);

private:
    int isLargeFile(std::string filename);

    //char *f;                /* name of file to get info on */
    //tm_zip *tmzip;             /* return value: access, modific. and creation times */
    //uLong *dt;             /* dostime */
    uLong filetime(const char* f, tm_zip *tmzip, uLong *dt);

};
    


#endif

 

FileZipper.cpp

#include "pch.h"
#include "FileZipper.hpp"

CFileZipper::CFileZipper()
{

}

CFileZipper::~CFileZipper()
{

}

int CFileZipper::isLargeFile(std::string filename)
{
    int largeFile = 0;
    ZPOS64_T pos = 0;
    FILE* pFile = NULL;
    //pFile = fopen64(filename.c_str(), "rb");
    fopen_s(&pFile, filename.c_str(), "rb");

    if (pFile != NULL)
    {
        int n = fseeko64(pFile, 0, SEEK_END);
        pos = ftello64(pFile);

        printf("File : %s is %lld bytes\n", filename.c_str(), pos);

        if (pos >= 0xffffffff)
            largeFile = 1;

        fclose(pFile);
    }

    return largeFile;
}

uLong CFileZipper::filetime(const char* f, tm_zip *tmzip, uLong *dt)
{
    int ret = 0;
    {
        FILETIME ftLocal;
        HANDLE hFind;
        WIN32_FIND_DATAA ff32;

        hFind = FindFirstFileA(f, &ff32);
        if (hFind != INVALID_HANDLE_VALUE)
        {
            FileTimeToLocalFileTime(&(ff32.ftLastWriteTime), &ftLocal);
            FileTimeToDosDateTime(&ftLocal, ((LPWORD)dt) + 1, ((LPWORD)dt) + 0);
            FindClose(hFind);
            ret = 1;
        }
}
    return ret;
}

int CFileZipper::ZipFiles(std::string &zipFileName, std::vector<std::string> files, bool bAppendFile, int nCompressLevel)
{
    int size_buf = WRITEBUFFERSIZE;
    void* buf = NULL;
    buf = (void*)malloc(size_buf);

    if (buf == NULL)
    {
        printf("Error allocating memory\n");
        return ZIP_INTERNALERROR;
    }

    zipFile zf;
    int err, errclose;
    zlib_filefunc64_def ffunc;
    fill_win32_filefunc64A(&ffunc);
    zf = zipOpen2_64(zipFileName.c_str(), (bAppendFile) ? 2 : 0, NULL, &ffunc);

    if (zf == NULL)
    {
        printf("error opening %s\n", zipFileName.c_str());
        err = ZIP_ERRNO;
    }
    else
    {
        printf("creating %s\n", zipFileName.c_str());
        err = ZIP_OK;
    }

    int i = 0;
    for (; i < files.size() && (err == ZIP_OK); i++)
    {
        FILE* fin = NULL;
        int size_read;
        std::string filenameinzip = files[i];
        std::string savefilenameinzip;
        zip_fileinfo zi;
        unsigned long crcFile = 0;
        int zip64 = 0;

        zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour =
            zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0;
        zi.dosDate = 0;
        zi.internal_fa = 0;
        zi.external_fa = 0;
        filetime(filenameinzip.c_str(), &zi.tmz_date, &zi.dosDate);

        zip64 = isLargeFile(filenameinzip);

        savefilenameinzip = filenameinzip.substr((filenameinzip.rfind('\\') + 1));

        err = zipOpenNewFileInZip3_64(zf, savefilenameinzip.c_str(), &zi,
            NULL, 0, NULL, 0, NULL /* comment*/,
            (nCompressLevel != 0) ? Z_DEFLATED : 0,
            nCompressLevel, 0,
            /* -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, */
            -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
            NULL, crcFile, zip64);

        if (err != ZIP_OK)
            printf("error in opening %s in zipfile\n", filenameinzip.c_str());
        else
        {
            //fin = fopen64(filenameinzip.c_str(), "rb");
            fopen_s(&fin, filenameinzip.c_str(), "rb");
            if (fin == NULL)
            {
                err = ZIP_ERRNO;
                printf("error in opening %s for reading\n", filenameinzip.c_str());
            }
        }

        if (err == ZIP_OK)
        {
            do
            {
                err = ZIP_OK;
                size_read = (int)fread(buf, 1, size_buf, fin);
                if (size_read < size_buf)
                    if (feof(fin) == 0)
                    {
                        printf("error in reading %s\n", filenameinzip.c_str());
                        err = ZIP_ERRNO;
                    }

                if (size_read > 0)
                {
                    err = zipWriteInFileInZip(zf, buf, size_read);
                    if (err < 0)
                    {
                        printf("error in writing %s in the zipfile\n",
                            filenameinzip.c_str());
                    }

                }
            } while ((err == ZIP_OK) && (size_read > 0));
        }

        if (fin)
            fclose(fin);

        if (err < 0)
            err = ZIP_ERRNO;
        else
        {
            err = zipCloseFileInZip(zf);
            if (err != ZIP_OK)
                printf("error in closing %s in the zipfile\n",
                    filenameinzip.c_str());
        }
    }

    errclose = zipClose(zf, NULL);
    if (errclose != ZIP_OK)
        printf("error in closing %s\n", zipFileName.c_str());

    if (buf != NULL)
        free(buf);

    return err;
}

 

zlibTest.cpp

#include "pch.h"
#include <iostream>
#include <stdio.h>
#include <vector>
#include <string>

#include "FileZipper.hpp"

int main()
{
    std::vector<std::string> files;
    files.push_back(std::string("D:\\test\\zlibTest\\1.txt"));
    files.push_back(std::string("D:\\test\\zlibTest\\2.txt"));
    files.push_back(std::string("D:\\test\\zlibTest\\3.txt"));

    std::string zipfileName(std::string("D:\\test\\zlibTest\\123.zip"));
    CFileZipper aZipper;
    aZipper.ZipFiles(zipfileName, files);

    return 0;

}

 

運行,在D:\test\zlibTest\目錄下生成了123.zip,解壓到另一目錄,用BCompare對比源文件,完 全 一 致

注意的是,123.zip的大小與1.txt和2.txt和3.txt這3個文件加起來一樣,是因為默認的壓縮等級為0,代表僅打包(在minizip.c中有提示),如果想完成壓縮效果可以設置壓縮等級,一般為8(minizip.c中的默認壓縮等級為8)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM