通過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文件格式做深入的了解,但是作為簡單的加密或者網絡傳輸還是有一定的參考意義的。