[Zlib]_[初级]_[使用zlib库压缩文件]

时间:2022-03-07 23:21:32


场景:

1. WIndows上没找到系统提供的win32 api来生成zip压缩文件, 有知道的大牛麻烦留个言。

2. zlib比较常用,编译也方便,使用它来做压缩吧。MacOSX平台默认支持zlib库.

http://zlib.net

3. zlib库里的 src\contrib\minizip\minizip.c  里有压缩例子, 我现在使用的是zlib 1.2.5,用vs2010编译完。下载地址:

http://download.csdn.net/detail/infoworld/8177625

4. 自己封装了一下ZipHelper便于使用,首先先得编译zlib为dll版本, 这个类就是删减了minizip.c的一些东西, 支持中文路径,项目需要目前只支持一级目录,如果有子目录的也不难,自己改改吧。

5. 使用方式, 注意, 路径字符串必须是utf8格式编码, 编译时要加上预编译宏 ZLIB_WINAPI

ZipHelper z;z.AddFile(utf8_path1);
z.AddFile(utf8_path2);
z.ToZip(utf8_output_zip_path);

6. MacOSX没测过,理论上应该可以编译过。 

zip_helper.h

#ifndef __ZIP_HELPER#define __ZIP_HELPER#include <vector>#include <string>//1.暂时不支持子目录//注意: 因为使用了zlib库,使用时加上预编译宏 ZLIB_WINAPIclass ZipHelper{public:ZipHelper(){}~ZipHelper(){}//path: utf8 pathZipHelper& AddFile(const char* input_path);//output_path :utf8 pathbool ToZip(const char* output_path);private:std::vector<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 _WIN32static 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);// 再转换为ANSIint 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 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;#endifZipHelper& ZipHelper::AddFile(const char* input_path){files_.push_back(input_path);return *this;}bool ZipHelper::ToZip(const char* output_path){int err=0;zipFile zf;int errclose;int opt_compress_level = Z_DEFAULT_COMPRESSION;#ifdef USEWIN32IOAPIzlib_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);#elsezf = zipOpen64(output_path,APPEND_STATUS_CREATE);#endifif (zf == NULL){printf("error opening %s\n",output_path);err= ZIP_ERRNO;return false;}int size = files_.size();void* buf = NULL;int size_buf = WRITEBUFFERSIZE;    buf = (void*)malloc(size_buf);for (int i = 0; i < size; ++i){FILE * fin;int size_read;const char* filenameinzip = files_[i].c_str();const char *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,&zi.tmz_date,&zi.dosDate);savefilenameinzip = filenameinzip;const char* pos = NULL;if( (pos = strrchr(savefilenameinzip,'\\')) || (pos = strrchr(savefilenameinzip,'/')) ){pos++;}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;}

注意: 再链接项目时如果报错, 那么就是因为你没加预编译宏 ZLIB_WINAPI

1>zip_helper.obj : error LNK2001: 无法解析的外部符号 _zipClose

完整项目下载地址:

http://download.csdn.net/detail/infoworld/9482396 (1.1 解决中文名在zip里的显示问题)

2017.3.5 更新

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