原文地址:http://blog.youkuaiyun.com/spacetiller/archive/2007/11/05/1867931.aspx
由于要用程序压缩一个文件夹,因此选用zlib库。
在zlib中的例子程序zpipe.c中,给出了如何压缩一个文件,这里稍加扩展,对一个文件夹进行压缩。
说来也简单,就是将文件夹/目录下的每个文件找到并压缩到一个文件中。
源代码如下:
- #include <stdio.h>
- #include <string.h>
- #include <assert.h>
- #include <dos.h>
- #include <direct.h>
- #include <zlib.h>
- #if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__)
- # include <fcntl.h>
- # include <io.h>
- # define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
- #else
- # define SET_BINARY_MODE(file)
- #endif
- #define CHUNK 16384
- //#define USE_TAG
- #ifdef USE_TAG
- #define COMPRESS_FILE_TAG_HEAD "<<<"
- #define COMPRESS_FILE_TAG_TAIL ">>>"
- #define COMPRESS_FILE_TAG_END_LEN 3 // must be strlen(COMPRESS_FILE_TAG_HEAD) = strlen(COMPRESS_FILE_TAG_TAIL)
- #else
- #define COMPRESS_FILE_TAG_HEAD ""
- #define COMPRESS_FILE_TAG_TAIL ""
- #define COMPRESS_FILE_TAG_END_LEN 0 // must be strlen(COMPRESS_FILE_TAG_HEAD) = strlen(COMPRESS_FILE_TAG_TAIL)
- #endif
- /**//* Compress from file source to file dest until EOF on source.
- def() returns Z_OK on success, Z_MEM_ERROR if memory could not be
- allocated for processing, Z_STREAM_ERROR if an invalid compression
- level is supplied, Z_VERSION_ERROR if the version of zlib.h and the
- version of the library linked do not match, or Z_ERRNO if there is
- an error reading or writing the files. */
- static int def(FILE *source, FILE *dest, int level)
- {
- int ret, flush;
- unsigned have;
- z_stream strm;
- unsigned char in[CHUNK];
- unsigned char out[CHUNK];
- /**//* allocate deflate state */
- strm.zalloc = Z_NULL;
- strm.zfree = Z_NULL;
- strm.opaque = Z_NULL;
- ret = deflateInit(&strm, level);
- if (ret != Z_OK)
- return ret;
- /**//* compress until end of file */
- do{
- strm.avail_in = fread(in, 1, CHUNK, source);
- if (ferror(source)){
- (void)deflateEnd(&strm);
- return Z_ERRNO;
- }
- flush = feof(source) ? Z_FINISH : Z_NO_FLUSH;
- strm.next_in = in;
- /**//* run deflate() on input until output buffer not full, finish
- compression if all of source has been read in */
- do{
- strm.avail_out = CHUNK;
- strm.next_out = out;
- ret = deflate(&strm, flush); /**//* no bad return value */
- assert(ret != Z_STREAM_ERROR); /**//* state not clobbered */
- have = CHUNK - strm.avail_out;
- if (fwrite(out, 1, have, dest) != have || ferror(dest)){
- (void)deflateEnd(&strm);
- return Z_ERRNO;
- }
- } while (strm.avail_out == 0);
- assert(strm.avail_in == 0); /**//* all input will be used */
- /**//* done when last data in file processed */
- } while (flush != Z_FINISH);
- assert(ret == Z_STREAM_END); /**//* stream will be complete */
- /**//* clean up and return */
- (void)deflateEnd(&strm);
- return Z_OK;
- }
- /**//* Decompress from file source to file dest until stream ends or EOF.
- inf() returns Z_OK on success, Z_MEM_ERROR if memory could not be
- allocated for processing, Z_DATA_ERROR if the deflate data is
- invalid or incomplete, Z_VERSION_ERROR if the version of zlib.h and
- the version of the library linked do not match, or Z_ERRNO if there
- is an error reading or writing the files. */
- static int inf(FILE *source, FILE *dest)
- {
- int ret;
- unsigned have;
- z_stream strm;
- unsigned char in[CHUNK];
- unsigned char out[CHUNK];
- /**//* allocate inflate state */
- strm.zalloc = Z_NULL;
- strm.zfree = Z_NULL;
- strm.opaque = Z_NULL;
- strm.avail_in = 0;
- strm.next_in = Z_NULL;
- ret = inflateInit(&strm);
- if (ret != Z_OK)
- return ret;
- /**//* decompress until deflate stream ends or end of file */
- do{
- strm.avail_in = fread(in, 1, CHUNK, source);
- if (ferror(source)){
- (void)inflateEnd(&strm);
- return Z_ERRNO;
- }
- if (strm.avail_in == 0)
- break;
- strm.next_in = in;
- /**//* run inflate() on input until output buffer not full */
- do{
- strm.avail_out = CHUNK;
- strm.next_out = out;
- ret = inflate(&strm, Z_NO_FLUSH);
- assert(ret != Z_STREAM_ERROR); /**//* state not clobbered */
- switch (ret){
- case Z_NEED_DICT:
- ret = Z_DATA_ERROR; /**//* and fall through */
- case Z_DATA_ERROR:
- case Z_MEM_ERROR:
- (void)inflateEnd(&strm);
- return ret;
- }
- have = CHUNK - strm.avail_out;
- if (fwrite(out, 1, have, dest) != have || ferror(dest)){
- (void)inflateEnd(&strm);
- return Z_ERRNO;
- }
- } while (strm.avail_out == 0);
- /**//* done when inflate() says it's done */
- } while (ret != Z_STREAM_END);
- /**//* clean up and return */
- (void)inflateEnd(&strm);
- return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
- }
- /**//* report a zlib or i/o error */
- static void zerr(int ret)
- {
- fputs("zpipe: ", stderr);
- switch (ret){
- case Z_ERRNO:
- if (ferror(stdin))
- fputs("error reading stdin ", stderr);
- if (ferror(stdout))
- fputs("error writing stdout ", stderr);
- break;
- case Z_STREAM_ERROR:
- fputs("invalid compression level ", stderr);
- break;
- case Z_DATA_ERROR:
- fputs("invalid or incomplete deflate data ", stderr);
- break;
- case Z_MEM_ERROR:
- fputs("out of memory ", stderr);
- break;
- case Z_VERSION_ERROR:
- fputs("zlib version mismatch! ", stderr);
- }
- }
- static int write_zfile_file_header(const char *file,FILE *zfile)
- {
- int len;
- len = strlen(file);
- if (fwrite(COMPRESS_FILE_TAG_HEAD, 1, COMPRESS_FILE_TAG_END_LEN, zfile) != COMPRESS_FILE_TAG_END_LEN || ferror(zfile))
- {
- fprintf(stderr,"When writing file or dir header to zfile: write error. ");
- return 1;
- }
- if (fwrite(file, 1, len, zfile) != len|| ferror(zfile))
- {
- fprintf(stderr,"When writing file or dir header to zfile: write error. ");
- return 1;
- }
- if (fwrite(COMPRESS_FILE_TAG_TAIL, 1, COMPRESS_FILE_TAG_END_LEN, zfile) != COMPRESS_FILE_TAG_END_LEN || ferror(zfile))
- {
- fprintf(stderr,"When writing file or dir header to zfile: write error. ");
- return 1;
- }
- return 0;
- }
- /* compress or decompress from stdin to stdout */
- static int compress_dir(char *file_in,FILE *fd_out)
- {
- FILE *fd_in;
- struct _finddata_t find_data;
- char file[128];
- long lf;
- int ret;
- write_zfile_file_header(file_in,fd_out);
- sprintf(file,"%s%s",file_in,"/*");
- if((lf = _findfirst(file,&find_data))==-1l) // LOOKOUT: not eleven, but one and lowercase 'L'
- {
- fprintf(stdout,"file not found. ");
- }
- else
- {
- do
- {
- if(!strcmp(find_data.name,".") || !strcmp(find_data.name,".."))
- continue;
- fprintf(stdout,"%s",find_data.name);
- sprintf(file,"%s%s%s",file_in,"/",find_data.name);
- if(find_data.attrib & _A_SUBDIR)
- {
- fprintf(stdout," ---directory--- ");
- ret = compress_dir(file,fd_out);
- }
- else
- {
- write_zfile_file_header(file,fd_out);
- if(access(file, 2) != 0) //W_OK=2
- {
- int attrib;
- attrib = _chmod(file,0);
- _chmod(file, attrib & ~_A_RDONLY);
- fprintf(stderr,"When writing file: No privilege to write file %s. ",file);
- return -1;
- }
- fd_in = fopen(file,"rb+");
- SET_BINARY_MODE(fd_in);
- ret = def(fd_in, fd_out, Z_DEFAULT_COMPRESSION);
- if (ret != Z_OK)
- zerr(ret);
- else
- fprintf(stdout," zip over ");
- fclose(fd_in);
- }
- }while( _findnext(lf, &find_data ) == 0 );
- }
- return 0;
- }
- int main(int argc, char **argv)
- {
- struct _finddata_t find_data;
- FILE *fd_in;
- FILE *fd_out;
- char *file_dir;
- char file_out[100];
- int ret;
- if (argc == 2)
- {
- file_dir = argv[1];
- if(_findfirst(file_dir,&find_data)==-1l) // LOOKOUT: not eleven, but one and lowercase 'L'
- {
- fprintf(stderr,"File or dir %s not found. ",file_dir);
- return 1;
- }
- if(find_data.attrib & _A_SUBDIR)
- {
- sprintf(file_out,"%s%s",file_dir,".z");
- fd_out = fopen(file_out,"wb+");
- SET_BINARY_MODE(fd_out);
- fprintf(stdout,"Dir %s being Compressed ... ",file_dir);
- ret = compress_dir(file_dir,fd_out);
- fclose(fd_out);
- }
- else
- {
- fprintf(stdout,"File %s being Compressed ... ",file_dir);
- sprintf(file_out,"%s%s",file_dir,".z");
- fd_in = fopen(file_dir,"rb+");
- fd_out = fopen(file_out,"wb+");
- SET_BINARY_MODE(fd_in);
- SET_BINARY_MODE(fd_out);
- ret = def(fd_in, fd_out, Z_DEFAULT_COMPRESSION);
- fclose(fd_in);
- fclose(fd_out);
- }
- if (ret != 0)
- {
- fprintf(stderr,"Compress Error !!!!!!!!!!!!!! ");
- zerr(ret);
- }
- else
- fprintf(stdout,"Compress OK--------------- ");
- }
- else {
- fprintf(stdout,"zod usage: zod [file]/[directory] ");
- }
- getchar();
- return 0;
- }
以上就是zpipe.c的几个主要函数:def()、inf()和zerr(),def()是压缩函数,主要使用了zlib的deflate()接口;inf()是压缩函数,主要使用了zlib的inflate()接口;zerr()是错误打印函数。