zlib 压缩解压 zip文件 带密码

69 篇文章 0 订阅
44 篇文章 0 订阅

使用zlib, 进行文件夹/文件进行加密压缩/解压缩

zlib_zip.h

#pragma once

// 压缩文件
int compress_zip_file(
    const char* input_path,                 // 输入路径(必须是已存在的文件或文件夹)
    const char* output_path,                // 输出文件路径
    const char* password                    // 密码(可为 NULL)
);

// 解压缩文件
int uncompress_zip_file(
    const char* input_file,                 // 输入文件路径(必须是 zip 文档)
    const char* output_dir,                 // 输出文件夹路径
    const char* password                    // 密码(可为 NULL)
);

zlib_zip.c

#include "zlib_zip.h"
#include <errno.h>
#include <malloc.h>
#include <sys/stat.h>
#include <io.h>
#include <time.h>
#include <direct.h>

#define FILE_PATH_MAX               (260)
#define FILE_READ_BUF_SIZE          (1024 * 1024)

#define ZLIB_WINAPI
#ifdef __cplusplus
extern "C"
{
#endif

#include "minizip/zip.h"
#include "minizip/unzip.h"

#ifdef __cplusplus
}
#endif

// 获取文件 CRC32
static int get_file_crc32(const char* file_path, unsigned long* crc_result)
{
    int err = ZIP_OK;
    FILE* input_file = NULL;
    void* input_buf = NULL;
    unsigned long calculate_crc = 0;
    size_t input_read_size = 0;

    do
    {
        // 打开文件
        err = fopen_s(&input_file, file_path, "rb");
        if (0 != err)
        {
            err = ZIP_ERRNO;
            break;
        }

        // 分配缓冲
        input_buf = malloc(FILE_READ_BUF_SIZE);
        if (NULL == input_buf)
        {
            err = ZIP_ERRNO;
            break;
        }

        while (1)
        {
            input_read_size = fread(input_buf, 1, FILE_READ_BUF_SIZE, input_file);
            if (input_read_size < 0)
            {
                err = ZIP_ERRNO;
                break;
            }

            if (0 == input_read_size)
            {
                break;
            }

            calculate_crc = crc32(calculate_crc, (const Bytef*)input_buf, (uInt)input_read_size);
            if (input_read_size < FILE_READ_BUF_SIZE)
            {
                break;
            }
        }

    } while (0);

    if (ZIP_OK == err && NULL != crc_result)
    {
        *crc_result = calculate_crc;
    }

    if (NULL != input_file)
    {
        fclose(input_file);
    }

    if (NULL != input_buf)
    {
        free(input_buf);
    }

    return err;
}

// 添加文件到 zip 文档
static int add_file_to_zip(
    zipFile* zip_file, 
    const char* file_path,
    const char* password
    )
{
    FILE* input_file = NULL;
    void* input_buf = NULL;
    errno_t err = 0;

    do
    {
        // 分配缓冲
        input_buf = malloc(FILE_READ_BUF_SIZE);
        if (NULL == input_buf)
        {
            err = ZIP_ERRNO;
            break;
        }

        // 打开文件
        err = fopen_s(&input_file, file_path, "rb");
        if (0 != err)
        {
            break;
        }

        zip_fileinfo zi = { 0 };
        struct stat stat_info = { 0 };
        struct tm file_date = { 0 };

        // 获取文件时间
        if (0 == stat(file_path, &stat_info))
        {
            localtime_s(&file_date, &stat_info.st_mtime);

            zi.tmz_date.tm_sec = file_date.tm_sec;
            zi.tmz_date.tm_min = file_date.tm_min;
            zi.tmz_date.tm_hour = file_date.tm_hour;
            zi.tmz_date.tm_mday = file_date.tm_mday;
            zi.tmz_date.tm_mon = file_date.tm_mon;
            zi.tmz_date.tm_year = file_date.tm_year;
        }

        zi.external_fa = _A_ARCH;

        uLong crc32 = 0;
        err = get_file_crc32(file_path, &crc32);
        if (ZIP_OK != err)
        {
            break;
        }

        err = zipOpenNewFileInZip3(
            zip_file, 
            file_path, 
            NULL, 
            NULL, 
            0, 
            NULL, 
            0, 
            NULL, 
            Z_DEFLATED, 
            Z_BEST_COMPRESSION, 
            0, 
            -MAX_WBITS, 
            DEF_MEM_LEVEL, 
            Z_DEFAULT_STRATEGY, 
            password, 
            crc32
        );

        if (ZIP_OK != err)
        {
            break;
        }

        // 写入 zip 文件
        size_t input_read_size = 0;
        while (TRUE)
        {
            // 读取输入数据
            input_read_size = fread_s(input_buf, FILE_READ_BUF_SIZE, 1, FILE_READ_BUF_SIZE, input_file);

            // 文件读取完毕退出循环
            if (0 == input_read_size)
            {
                break;
            }

            // 发生错误则退出循环
            if (0 != ferror(input_file))
            {
                err = ZIP_ERRNO;
                break;
            }

            // 将数据写入 zip 中的文件
            err = zipWriteInFileInZip(zip_file, input_buf, (unsigned int)input_read_size);
            if (ZIP_OK != err)
            {
                break;
            }

            if (input_read_size < FILE_READ_BUF_SIZE)
            {
                break;
            }
        }

        zipCloseFileInZip(zip_file);

    } while (0);

    if (NULL != input_file)
    {
        fclose(input_file);
    }

    if (NULL != input_buf)
    {
        free(input_buf);
    }

    return err;
}

// 添加路径到 zip 文档
static int add_path_to_zip(
    zipFile* zip_file, 
    const char* path_name,
    const char* password
)
{
    char file_path[FILE_PATH_MAX] = { 0 };
    struct _finddata_t  find_data = { 0 };
    struct stat buf = { 0 };
    errno_t err = 0;

    if ('\0' != *path_name)
    {
        err = stat(path_name, &buf);
        if (0 != err)
        {
            return err;
        }
    }
    else
    {
        buf.st_mode = S_IFDIR;
    }

    // 检查是否为文件夹
    if (S_IFDIR & buf.st_mode)
    {
        // 拼接得到遍历路径
        strcpy_s(file_path, sizeof(file_path), path_name);

        if ('\0' != *path_name)
        {
            strcat_s(file_path, sizeof(file_path), "/");
        }

        strcat_s(file_path, sizeof(file_path), "*.*");
        intptr_t find_handle = _findfirst(file_path, &find_data);
        if (0 == find_handle)
        {
            err = ZIP_ERRNO;
            return err;
        }

        do
        {
            // 拼接文件路径
            strcpy_s(file_path, sizeof(file_path), path_name);
            if ('\0' != *path_name)
            {
                strcat_s(file_path, sizeof(file_path), "/");
            }
            strcat_s(file_path, sizeof(file_path), find_data.name);

            // 上一级目录与当前目录跳过
            if (0 == _stricmp("..", find_data.name) || 0 == _stricmp(".", find_data.name))
            {
                continue;
            }

            // 文件夹则递归处理
            if (_A_SUBDIR & find_data.attrib)
            {
                zip_fileinfo zi = { 0 };
                struct stat stat_info = { 0 };
                struct tm file_date = { 0 };

                // 获取文件时间
                if (0 == stat(path_name, &stat_info))
                {
                    localtime_s(&file_date, &stat_info.st_mtime);

                    zi.tmz_date.tm_sec = file_date.tm_sec;
                    zi.tmz_date.tm_min = file_date.tm_min;
                    zi.tmz_date.tm_hour = file_date.tm_hour;
                    zi.tmz_date.tm_mday = file_date.tm_mday;
                    zi.tmz_date.tm_mon = file_date.tm_mon;
                    zi.tmz_date.tm_year = file_date.tm_year;
                }

                zi.external_fa = _A_ARCH | _A_SUBDIR;

                // 拼接文件路径
                strcpy_s(file_path, sizeof(file_path), path_name);
                if ('\0' != *path_name)
                {
                    strcat_s(file_path, sizeof(file_path), "/");
                }
                strcat_s(file_path, sizeof(file_path), find_data.name);
                strcat_s(file_path, sizeof(file_path), "/");

                // 在 zip 文件中创建新文件
                if (ZIP_OK != zipOpenNewFileInZip(zip_file, file_path, &zi, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION))
                {
                    break;
                }

                err = zipCloseFileInZip(zip_file);
                if (ZIP_OK != err)
                {
                    break;
                }

                // 拼接文件路径
                strcpy_s(file_path, sizeof(file_path), path_name);
                if ('\0' != *path_name)
                {
                    strcat_s(file_path, sizeof(file_path), "/");
                }
                strcat_s(file_path, sizeof(file_path), find_data.name);

                if (ZIP_OK != add_path_to_zip(zip_file, file_path, password))
                {
                    break;
                }
            }
            else
            {
                err = add_file_to_zip(zip_file, file_path, password);
                if (EACCES == err)
                {
                    continue;
                }

                if (ZIP_OK != err)
                {
                    break;
                }
            }

        } while (0 == _findnext(find_handle, &find_data));

        _findclose(find_handle);
    }
    else
    {
        return add_file_to_zip(zip_file, path_name, password);
    }

    return err;
}

// 创建文件夹
static errno_t create_directory(const char* input_path)
{
    char dir_buf[FILE_PATH_MAX] = { 0 };
    struct stat buf = { 0 };
    errno_t err = 0;
    const char* dir_path = input_path;

    while ('\0' != *dir_path)
    {
        dir_path++;

        if ('/' == *dir_path)
        {
            strncpy_s(dir_buf, sizeof(dir_buf), input_path, dir_path - input_path);
            err = stat(dir_buf, &buf); 
            if ((0 == err))
            {
                // 已存在路径但不是文件夹则终止处理
                if (!(S_IFDIR & buf.st_mode))
                {
                    err = ENOENT;
                    break;
                }
            }
            else
            {
                // 文件夹不存在则创建
                err = _mkdir(dir_buf);
            }

            if (0 != err)
            {
                break;
            }
        }
    }

    return err;
}

// 压缩文件
int compress_zip_file(
    const char* input_path,                 // 输入路径(必须是已存在的文件或文件夹)
    const char* output_path,                // 输出文件路径
    const char* password                    // 密码
)
{
    errno_t err = ZIP_OK;

    if (NULL == input_path || NULL == output_path)
    {
        return ZIP_PARAMERROR;
    }

    if ('\0' == *input_path || '\0' == *output_path)
    {
        return ZIP_PARAMERROR;
    }

    do
    {
        // 创建 zip 文件
        zipFile zFile = zipOpen(output_path, 0);
        if (NULL == zFile)
        {
            err = ZIP_ERRNO;
            break;
        }

        // 添加 路径到 zip 文件
        err = add_path_to_zip(zFile, input_path, password);
        if(ZIP_OK != err)
        {
            err = ZIP_ERRNO;
            break;
        }

        // 关闭 zip 文件
        err = zipClose(zFile, NULL);
        if(ZIP_OK != err)
        {
            err = ZIP_ERRNO;
            break;
        }

        err = ZIP_OK;

    } while (0);

    return err;
}

// 解压缩文件
int uncompress_zip_file(
    const char* input_file,                 // 输入文件路径
    const char* output_dir,                 // 输出文件夹路径
    const char* password                    // 密码
)
{
    char file_path[FILE_PATH_MAX] = { 0 };
    unzFile unzFile = NULL;
    void* input_buf = NULL;
    errno_t err = 0;

    if (NULL == input_file || NULL == output_dir)
    {
        return UNZ_PARAMERROR;
    }

    do
    {
        unzFile = unzOpen(input_file);
        if (NULL == unzFile)
        {
            err = UNZ_ERRNO;
            break;
        }

        input_buf = malloc(FILE_READ_BUF_SIZE);
        if (NULL == input_buf)
        {
            err = UNZ_ERRNO;
            break;
        }

        unz_global_info global_info = { 0 };
        err = unzGetGlobalInfo(unzFile, &global_info);
        if (UNZ_OK != err)
        {
            break;
        }
        
        for (uLong i = 0; i < global_info.number_entry; i++)
        {
            char file_name[FILE_PATH_MAX] = { 0 };
            unz_file_info file_info = { 0 };

            // 获取文件信息
            err = unzGetCurrentFileInfo(unzFile, &file_info, file_name, sizeof(file_name), NULL, 0, NULL, 0);
            if (UNZ_OK != err)
            {
                break;
            }

            // 拼接文件路径
            strcpy_s(file_path, sizeof(file_path), output_dir);
            if ('\0' != output_dir[0])
            {
                strcat_s(file_path, sizeof(file_path), "/");
            }
            strcat_s(file_path, sizeof(file_path), file_name);

            // 检查是否为文件夹
            if (_A_SUBDIR & file_info.external_fa)
            {
                err = create_directory(file_path);
                if (UNZ_OK != err)
                {
                    break;
                }
            }
            else
            {
                FILE* output_file = NULL;

                // 打开当前文件
                err = unzOpenCurrentFilePassword(unzFile, password);
                if (UNZ_OK != err)
                {
                    break;
                }

                // 打开输出文件
                err = fopen_s(&output_file, file_path, "wb");
                if (0 != err)
                {
                    err = UNZ_ERRNO;
                    break;
                }

                while (1)
                {
                    // 读取数据
                    int input_read_size = unzReadCurrentFile(unzFile, input_buf, FILE_READ_BUF_SIZE);
                    if (input_read_size < 0)
                    {
                        err = UNZ_ERRNO;
                        break;
                    }

                    if (input_read_size == 0)
                    {
                        break;
                    }

                    // 输出数据
                    if (input_read_size != fwrite(input_buf, 1, input_read_size, output_file))
                    {
                        err = UNZ_ERRNO;
                        break;
                    }

                    if (input_read_size < FILE_READ_BUF_SIZE)
                    {
                        break;
                    }
                }

                fclose(output_file);

                err = unzCloseCurrentFile(unzFile);
                if (UNZ_OK != err)
                {
                    break;
                }

            }

            // 转到下一个文件
            err = unzGoToNextFile(unzFile);
            if (UNZ_OK != err)
            {
                if (UNZ_END_OF_LIST_OF_FILE == err)
                {
                    err = UNZ_OK;
                }

                break;
            }
        }
        
    } while (0);

    // 关闭 zip 文件
    if (NULL != unzFile)
    {
        unzClose(unzFile);
    }

    // 释放读取缓冲
    if (NULL != input_buf)
    {
        free(input_buf);
    }

    return err;
}

测试

main.c

#include "zlib_zip.h"

int main()
{
    compress_zip_file("zlib 1.3.1", "2024.zip", "12345678");
    uncompress_zip_file("2024.zip", "2024", "12345678");
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值