[Zlib]_[初级]_[使用zlib库压缩目录]

3/8/2017来源:ASP.NET技巧人气:1904

场景 http://blog.csdn.net/infoworld/article/details/60480313

压缩目录为zip不用多说了, 很多场景都会用到, 比如打包文件, 打包目录下载等.

说明

zlib里的minizip并不可以直接使用来压缩文件夹, 但并不妨碍我们借鉴它的代码. 关键其实就在这个变量里savefilenameinzip, 它支持目录结构的名字. 所以只需要在调用 zipOpenNewFileInZip3_64 时, 传递带相对目录结构的savefilenameinzip即可. 注: 可能最新版的zlibminizip.c已支持, 我用的是1.2.5版本.

在之前的 使用zlib库压缩文件 里, 我们使用了ZipHelper 来压缩文件到直接目录, 这次就稍微改改就可以压缩目录. 接口使用utf8编码的字符串, 目的是以后能扩展支持macOS平台. 注意在编译时要加宏 ZLIB_WINAPI

例子

zip_helper.h

#ifndef __ZIP_HELPER #define __ZIP_HELPER #include <map> #include <string> //1.暂时不支持子目录 //注意: 因为使用了zlib库,使用时加上预编译宏 ZLIB_WINAPI class ZipHelper { public: ZipHelper(){} ~ZipHelper(){} //path: utf8 path ZipHelper& AddFile(const char* input_path,const char* inzip_path = ""); ZipHelper& AddDir(const char* input_dir,const char* temp_dir = NULL); //output_path :utf8 path bool ToZip(const char* output_path); PRivate: std::map<std::string,std::string> files_; }; #endif

zip_helper.cpp

#include "zip_helper.h" #ifndef _WIN32 #ifndef __USE_FILE_OFFSET64 #define __USE_FILE_OFFSET64 #endif #ifndef __USE_LARGEFILE64 #define __USE_LARGEFILE64 #endif #ifndef _LARGEFILE64_SOURCE #define _LARGEFILE64_SOURCE #endif #ifndef _FILE_OFFSET_BIT #define _FILE_OFFSET_BIT 64 #endif #endif #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <errno.h> #include <fcntl.h> #include <direct.h> #include <io.h> #include "zlib.h" #include "zip.h" #ifdef _WIN32 #define USEWIN32IOAPI #include "iowin32.h" #endif #define WRITEBUFFERSIZE (16384) #define MAXFILENAME (256) #ifdef _WIN32 static char* Utf8ToAnsi(const char* utf8) { // 先转换为UNICODE int dwUnicodeLen = MultiByteToWideChar(CP_UTF8,0,utf8,-1,NULL,0); if(!dwUnicodeLen) { return strdup(utf8); } size_t num = dwUnicodeLen*sizeof(wchar_t); wchar_t *pwText = (wchar_t*)malloc(num+2); memset(pwText,0,num+2); MultiByteToWideChar(CP_UTF8,0,utf8,-1,pwText,dwUnicodeLen); // 再转换为ANSI int len; len = WideCharToMultiByte(CP_ACP, 0, pwText, -1, NULL, 0, NULL, NULL); char *szANSI = (char*)malloc(len + 1); memset(szANSI, 0, len + 1); WideCharToMultiByte(CP_ACP, 0, pwText, -1, szANSI, len, NULL,NULL); free(pwText); return (char*)szANSI; } static wchar_t* QXUtf82Unicode(const char* utf) { if(!utf || !strlen(utf)) { return NULL; } int dwUnicodeLen = MultiByteToWideChar(CP_UTF8,0,utf,-1,NULL,0); size_t num = dwUnicodeLen*sizeof(wchar_t); wchar_t *pwText = (wchar_t*)malloc(num); memset(pwText,0,num); MultiByteToWideChar(CP_UTF8,0,utf,-1,pwText,dwUnicodeLen); return pwText; } static char* QXUnicode2Utf8(const wchar_t* unicode) { if(unicode == NULL) { return strdup("\0"); } int len; len = WideCharToMultiByte(CP_UTF8, 0,unicode, -1, NULL, 0, NULL, NULL); char *szUtf8 = (char*)malloc(len + 1); memset(szUtf8, 0, len + 1); WideCharToMultiByte(CP_UTF8, 0,unicode, -1, szUtf8, len, NULL,NULL); return szUtf8; } static FILE* ZipFopen(const char* path,const char* mode) { wchar_t* path_u = QXUtf82Unicode(path); wchar_t* mode_u = QXUtf82Unicode(mode); FILE* file = _wfopen(path_u,mode_u); free(path_u); free(mode_u); return file; } /* name of file to get info on */ /* return value: access, modific. and creation times */ /* dostime */ uLong filetime(const char* f, tm_zip *tmzip, uLong *dt) { int ret = 0; { FILETIME ftLocal; HANDLE hFind; WIN32_FIND_DATA ff32; wchar_t *unicode = QXUtf82Unicode(f); hFind = FindFirstFile(unicode,&ff32); if (hFind != INVALID_HANDLE_VALUE) { FileTimeToLocalFileTime(&(ff32.ftLastWriteTime),&ftLocal); FileTimeToDosDateTime(&ftLocal,((LPWord)dt)+1,((LPWORD)dt)+0); FindClose(hFind); ret = 1; } free(unicode); } return ret; } #else #define ZipFopen fopen; #endif ZipHelper& ZipHelper::AddFile(const char* input_path,const char* inzip_path) { files_[input_path] = inzip_path; return *this; } ZipHelper& ZipHelper::AddDir(const char* input_dir,const char* temp_dir){ WIN32_FIND_DATA findFileData; auto input_dirw = QXUtf82Unicode(input_dir); std::wstring path(input_dirw); auto pos = path.at(path.size()-1); if(pos != L'\\' && pos != L'/'){ path.append(L"/"); } HANDLE hFind = ::FindFirstFile((path+L"*").c_str(),&findFileData); size_t file_name_len = 0; if (hFind == INVALID_HANDLE_VALUE){ free(input_dirw); return *this; }else{ if(!temp_dir){ temp_dir = input_dir; } std::string temp_dir2(temp_dir); pos = temp_dir2.at(temp_dir2.size()-1); if(pos != '\\' && pos != '/'){ temp_dir2.append("/"); } while (FindNextFile(hFind, &findFileData)){ if(!wcscmp(findFileData.cFileName,L".") || !wcscmp(findFileData.cFileName,L"..")) continue; std::wstring path1(path); path1.append(findFileData.cFileName); char* path_utf8 = QXUnicode2Utf8(path1.c_str()); if(findFileData.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY){ AddDir(path_utf8,temp_dir); }else{ AddFile(path_utf8,path_utf8+strlen(temp_dir2.c_str())); } free(path_utf8); } FindClose(hFind); } free(input_dirw); } bool ZipHelper::ToZip(const char* output_path) { int err=0; zipFile zf; int errclose; int opt_compress_level = Z_DEFAULT_COMPRESSION; #ifdef USEWIN32IOAPI zlib_filefunc64_def ffunc; fill_win32_filefunc64W(&ffunc); wchar_t* temp_path = QXUtf82Unicode(output_path); zf = zipOpen2_64(temp_path,APPEND_STATUS_CREATE,NULL,&ffunc); free(temp_path); #else zf = zipOpen64(output_path,APPEND_STATUS_CREATE); #endif if (zf == NULL) { printf("error opening %s\n",output_path); err= ZIP_ERRNO; return false; } void* buf = NULL; int size_buf = WRITEBUFFERSIZE; buf = (void*)malloc(size_buf); for (auto ite = files_.begin(); ite != files_.end(); ++ite) { FILE * fin; int size_read; const char* filenameinzip = ite->first.c_str(); const char *savefilenameinzip = ite->second.c_str(); 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,&zi.tmz_date,&zi.dosDate); const char* pos = NULL; if(!strlen(savefilenameinzip)){ savefilenameinzip = filenameinzip; if( (pos = strrchr(savefilenameinzip,'\\')) || (pos = strrchr(savefilenameinzip,'/')) ){ pos++; }else{ pos = savefilenameinzip; } }else{ pos = savefilenameinzip; } // 这个版本不支持UTF8字符串的正确存储,所以要转换为ANSI显示. char* pos_ansi = Utf8ToAnsi(pos); err = zipOpenNewFileInZip3_64(zf,pos_ansi,&zi, NULL,0,NULL,0,NULL, (opt_compress_level != 0) ? Z_DEFLATED : 0, opt_compress_level,0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, NULL,crcFile, zip64); free(pos_ansi); if (err != ZIP_OK) { printf("error in opening %s in zipfile\n",pos); } else { fin = ZipFopen(filenameinzip,"rb"); if (fin==NULL) { err=ZIP_ERRNO; printf("error in opening %s for reading\n",filenameinzip); } } 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); 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); } } } 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); } } } errclose = zipClose(zf,NULL); if (errclose != ZIP_OK) { printf("error in closing %s\n",output_path); return false; } return true; }

main.cpp

#include "zip_helper.h" int main(int argc,char* argv[]){ ZipHelper zh; zh.AddDir("Win32"); zh.AddFile("./main.cpp"); zh.ToZip("1.zip"); }

项目下载路径

参考

minizip File Attribute Constants FindFirstFile 使用zlib库压缩文件