zlib压缩和解压文件的实现
通过zlib库是可以实现压缩和解压缩文件,或者是对字节流进行压缩、加密等功能。
这里实现了一个对文件的压缩和解压程序。
1. 函数原型
//compress a file int compressFile(const char *srcfile, unsigned long *srclen, const char *destfile, unsigned long *destlen); //decompress a file int decompressFile(const char *srcfile, unsigned long *srclen, const char *destfile, unsigned long *destlen);
srcfile和destfile是源文件和目标文件的地址,srclen和destlen是表示源文件和压缩文件的大小,该值通过引用传递;
如果程序执行成功,返回0,其他值表示错误,详细错误见代码。
2. 头文件等
#include <unistd.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "zlib.h" #define CHUNK 16384 typedef union { unsigned char c[sizeof(unsigned int)]; unsigned int size; } cpsize_t;
这里说明一下这个cpsize_t的联合体,因为我们采用每次按CHUNK大小连续压缩文件,但是不知道每次压缩以后的大小,所以需要有一个额外的信息,来标识压缩后的大小,这里就用了一个无符号的整型,但是为了便于后面写文件操作,定义一个字符数组,将uint按字节存取。不过这个地方会涉及到大端字序和小端字序的问题,在测试时,我们假设压缩端和解压缩端平台相同,真正使用的时候,还是要注意这个问题的。
3. 主程序
int main(int argc, char **argv) { unsigned long s1, s2; int ret; if (argc != 4) { printf("usage %s -[c|d] srcfile destfile\n", argv[0]); printf("-c\tcompress the srcfile, and save compressed file as destFile.\n"); printf("-d\tdecompress the srcfile, and save decompressed file as destFile.\n"); return 0; } if (strcmp(argv[1], "-c") == 0) //compress file { ret = compressFile(argv[2], &s1, argv[3], &s2); if (0 == ret) { printf("Compression complete, Before:%ld Bytes(s)\tAfter:%ld Bytes(s)\t Ratio:%0.2f%%\n", s1, s2, 1.0f * s2 / s1 * 100); return 0; } else { printf("Compression failed, error code=%d\n", ret); return ret; } } if (strcmp(argv[1], "-d") == 0) //decompress file { ret = decompressFile(argv[2], &s1, argv[3], &s2); if (0 == ret) { printf("Deompression complete, Before:%ld Bytes(s)\tAfter:%ld Bytes(s)\t Ratio:%0.2f%%\n", s1, s2, 1.0f * s2 / s1 * 100); return 0; } else { printf("Deompression failed, error code=%d\n", ret); return ret; } } return 0; }
根据选项决定是压缩还是解压缩文件。
4. 压缩函数
int compressFile(const char *srcfile, unsigned long *srclen, const char *destfile, unsigned long *destlen) { char rdbuff[CHUNK] = {0}; char* wrbuff=NULL; int rdfd, wrfd; cpsize_t cps; cps.size = 0; unsigned long nread, nwrite; *srclen = 0; *destlen = 0; rdfd = open(srcfile, O_RDONLY); if (rdfd < 0) { printf("open input file failed.\n"); return -1; } wrfd = open(destfile, O_WRONLY | O_CREAT, 0755); if (wrfd < 0) { close(rdfd); printf("open output file failed.\n"); return -1; } while ((nread = read(rdfd, rdbuff, CHUNK)) > 0) { *srclen += nread; nwrite = compressBound(nread); wrbuff=(char*)malloc(nwrite); if (compress(wrbuff, &nwrite, rdbuff, nread) != Z_OK) { printf("compress error occur.\n"); free(wrbuff); return -2; } *destlen += nwrite; cps.size = nwrite; write(wrfd, cps.c, sizeof(unsigned int)); //mark each chunk data size write(wrfd, wrbuff, nwrite); free(wrbuff); } close(wrfd); close(rdfd); return 0; }
5. 解压函数
//decompress a file int decompressFile(const char *srcfile, unsigned long *srclen, const char *destfile, unsigned long *destlen) { char *rdbuff = NULL; char wrbuff[CHUNK] = {0}; cpsize_t cps; cps.size = 0; int rdfd, wrfd; unsigned long nread, nwrite, total_write = 0; *srclen = 0; *destlen = 0; rdfd = open(srcfile, O_RDONLY); if (rdfd < 0) { perror("open input file failed.\n"); return -1; } wrfd = open(destfile, O_WRONLY | O_CREAT, 0755); if (wrfd < 0) { close(rdfd); printf("open output file failed.\n"); return -1; } while ((nread = read(rdfd, cps.c, sizeof(unsigned int))) == sizeof(unsigned int)) { rdbuff = (char *)malloc(cps.size); nread = read(rdfd, rdbuff, cps.size); *srclen += nread; if (nread != cps.size) { //read chunk not match, error } nwrite = CHUNK; if (uncompress(wrbuff, &nwrite, rdbuff, nread) != Z_OK) { printf("decompress error occur.\n"); free(rdbuff); close(wrfd); close(rdfd); return -3; } else { *destlen += nwrite; nwrite = write(wrfd, wrbuff, nwrite); free(rdbuff); } } close(wrfd); close(rdfd); return 0; }
6. 测试
这个程序还不能够像zip应用程序那样压缩多个文件,操作该类型的文件需要对zip文件格式做深入的了解,但是作为简单的加密或者网络传输还是有一定的参考意义的。