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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM