使用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;
}