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文件格式做深入的了解,但是作为简单的加密或者网络传输还是有一定的参考意义的。

 

posted @ 2021-05-19 18:32  castor_xu  阅读(6102)  评论(0编辑  收藏  举报