要把几个文件合并成一个压缩文件,首先想到的开源库就是zlib
其实使用哪个格式都可以,我这里选的是zip格式,下载之后解压
因为我使用的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
保存,重新编译,成功
全部生成也可以生成minizip,这时候就可以通过debug学习minizip的使用过程了。
用到的几个主要函数如下:
zipOpen2_64 用于创建一个新的zip文件
根据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)
原文:https://www.cnblogs.com/Sseakompp/p/12133869.html