[Zlib]_[0基础]_[使用zlib库压缩文件]
场景:
1. WIndows上没找到系统提供的win32 api来生成zip压缩文件, 有知道的大牛麻烦留个言。
2. zlib比較经常使用,编译也方便,使用它来做压缩吧。
MacOSX平台默认支持zlib库.
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_WINAPI class ZipHelper { public: ZipHelper(){} ~ZipHelper(){} //path: utf8 path ZipHelper& AddFile(const char* input_path); //output_path :utf8 path bool 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 _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 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) { 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 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; } 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 更新