由于要用程序压缩一个文件夹,因此选用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);
}
}
#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);
}
}
以上就是zpipe.c的几个主要函数:def()、inf()和zerr(),def()是压缩函数,主要使用了zlib的deflate()接口;inf()是压缩函数,主要使用了zlib的inflate()接口;zerr()是错误打印函数。
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,1,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;
const 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] ");
}
getch();
return 0;
}
... {
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,1,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;
const 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] ");
}
getch();
return 0;
}
以上就是主要的目录压缩代码,主要是将目录/文件的名称写入后,紧跟着压缩后的数据。
这里只提供了压缩代码,解压代码也依次逆向做出;在解压的时候,有个问题:怎样知道压缩数据开始?这里提供了USE_TAG进行分隔,若诸位有更好的方法,请告诉我。
注意:这种格式并不通用,要根据你的实际格式要求进行压缩!
仅供参考。