[C/C++]_[初级]_[使用zlib库压缩文件]

场景:

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没测过,理论上应该可以编译过。

7. 有帮助的帮忙顶下或留个言.

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 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;
		}

		err = zipOpenNewFileInZip3_64(zf,pos,&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);

		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
时间: 2024-11-16 19:00:47

[C/C++]_[初级]_[使用zlib库压缩文件]的相关文章

[Windows]_[初级]_[Release程序的崩溃报告minidump解决方案]

场景: 1. Release的程序崩溃时,崩溃报告可以让开发人员查明代码哪里出了问题,用处大大的. 2. 只有用VS的编译器才支持,所以MinGW就无缘了. 3. 使用了未处理异常过滤处理函数. 4. 生成的.dmp文件用zlib库压缩, 用到以下的ZipHelper类,编译时还是需要zlib库和dbghelp.lib http://blog.csdn.net/infoworld/article/details/41290969 5. 使用方式就是把DbgReport作为app类的成员变量,或者

[Zlib]_[初级]_[使用zlib库解压提取文件]

场景: 1. zlib库跨平台,Windows和MacOSX都可以使用,还支持64位编译,轻量级,没有不用的道理. 2. 处理.zip,apk,docx文件时,因为这类文件都是zip格式,使用zlib能方便提取压缩文件里的数据. 方法: 1. 除了要使用zlib库本身,还需要使用zlib里的contrib目录minizip部分头文件和.c文件. zlib-1.2.5/src/contrib/minizip/unzip.h unzip.c,ioapi.c,ioapi.h (windows还需要 i

[zlib]_[初级]_[使用Zlib完整解压zip内容]

场景: 1. 解压文件一般用在下载了一个zip文件之后解压,或者分析某个文件需要解压的操作上. 2. 解压文件,特别是解压带文件夹的zip文件往往系统没有提供这类Win32 API,当然C#自带库能解压, 当然这里只讨论C/C++, 像C#和Java这种开挂的标准库不在考虑范围内. 3. zlib解压文件的使用例子在 contrib\minizip 例子里. 这里基本是直接提取miniunz.c 的代码进行封装解压即可, 只是改了下支持中文路径. 主文件 zip_util.cpp #includ

使用Zlib库进行文件的压缩和解压

zlib介绍 zlib是提供数据压缩用的函式库,由Jean-loup Gailly与Mark Adler所开发,初版0.9版在1995年5月1日发表.zlib使用DEFLATE算法,最初是为libpng函式库所写的,后来普遍为许多软件所使用.此函式库为自由软件,使用zlib授权 配置 我是从网上直接下载了zlib的dll文件的,压缩包具体有几个部分,分别是头文件zconf.h,zlib.h:lib文件zdll.lib:dll文件zlib1.dll. 配置过程很简单,包含头文件目录或引入头文件:配

[C/C++11]_[初级]_[使用正则表达式库regex]

场景 正则表达式在处理非常量字符串查找,替换时能很省事,如果稍微复杂点的字符串匹配, 没有正则表达式还真做不出来. C++11 为我们提供了正则表达式库. 使用起来比boost的正则库方便. 搞Java 的一定觉得很搞笑,这都是Java的标配功能, 怎么C++11才支持这个库,vs2010 以才支持.建议在处理字符串搜索替换时,直接用正则吧,代码量少,快速. 参考 std::regex_replace std::regex_iterator Regular Expressions (C++) 说

[C/C++标准库]_[初级]_[交集和补集]

场景: 1. 计算std::vector A和 std::vector B里的相同的元素, 用于保留不删除. 2. 计算std::vector A和 std::vector B里各自的补集, 用于删除A的补集和添加B的补集,用在一些更新关联表的操作里. 比如联系人A所属分组B是一个集合BV, 把联系人A的所属分组 修改为集合CV, 就需要删除两个集合BV,CV的CV补集和新增BV补集. 3. C++标准库为我们提供了这些算法. 代码: // test_AndroidAssistant.cpp :

[C/C++标准库]_[初级]_[使用ctype里的isxxx函数时要注意的事项]

场景: 1. 标准库里的 ctype.h里的函数是用于1个字节的判断的,但是参数却是int, 这样很容易导致误用. isalpha iscntrl isdigit isgraph isprint ispunct isspace isxdigit isalnum islower isupper int isspace( int ch ); 最恶心的是vc++的实现会对超过1字节的值会直接崩溃,gcc不会!!! #if defined (_DEBUG) extern "C" int __c

[C/C++标准库]_[初级]_[使用模板删除字符串前后空格((w)string space)]

场景: 1. C++没有提供删除std::(w)string的前后空格的函数,比如TrimSpace. 2. 很多库都提供, 但是为了移植代码方便,最好还是能用标准库解决就用标准库. 下边用模板实现了移除空格的函数. test.cpp #include <iostream> #include <stdlib.h> #include <string.h> #include <string> #include <ctype.h> using name

[C/C++标准库]_[初级]_[使用fstream合并文本文件]

场景: 1. 就是合并文本文件,并且从第2个文件起不要合并第一行. 2. 多加了一个功能,就是支持2个以上的文件合并. 3. 问题: http://ask.csdn.net/questions/192151 只能说很简单: 基础不过关吧,这位同学,也有可能不是开发的,放这里也是为了培训基础差的. test.cpp #include <fstream> #include <string> #include <iostream> using namespace std; /