用zlib压缩文件夹

由于要用程序压缩一个文件夹,因此选用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(in1, 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(out1, 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(in1, 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(out1, 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;
}

    以上就是主要的目录压缩代码,主要是将目录/文件的名称写入后,紧跟着压缩后的数据

    这里只提供了压缩代码,解压代码也依次逆向做出;在解压的时候,有个问题:怎样知道压缩数据开始?这里提供了USE_TAG进行分隔,若诸位有更好的方法,请告诉我。

    注意:这种格式并不通用,要根据你的实际格式要求进行压缩!

    仅供参考。 

猜你喜欢

转载自blog.csdn.net/spacetiller/article/details/1867931