用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项目下内容如下:

扫描二维码关注公众号,回复: 8396749 查看本文章

其中编译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)

猜你喜欢

转载自www.cnblogs.com/Sseakompp/p/12133869.html
今日推荐