利用美团longcat.ai编写的C语言支持指定压缩算法通用ZIP压缩程序

提示词:请用c编写支持指定压缩算法的通用zip程序,支持打包整个目录和使用文件通配符

原本以为他会调用infozip的libzip库或zlib的minizip库,没想到他完全只依赖zlib库,没有用到其他的zip实现,用770行左右源码就实现了所需功能。

缺点也不是没有,原始实现少包含了一些系统头文件,有的地方释放指针指向的内存有错,暂时用注释掉free的办法屏蔽了。压缩目录时,压缩包中的文件和目录都多了"/"前缀,我用字符串指针值+1方法绕过了。

c 复制代码
//# C语言通用ZIP压缩程序设计方案

//## 概述
//以下是一个支持多种压缩算法、目录打包和文件通配符的通用ZIP程序设计方案。该程序将使用zlib库作为压缩后端,支持递归目录遍历和通配符匹配。

//## 核心模块设计

//### 1. 依赖库

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#include <zlib.h>
#include <fnmatch.h>  // 用于通配符匹配
#include <time.h>

#include <stdint.h>
#include <getopt.h>
#include <libgen.h>
// 条目数组操作
#define ZIP_ENTRY_INIT_CAPACITY 128
#define ZIP_ENTRY_GROWTH_FACTOR 1.5

// 默认值
#define DEFAULT_COMPRESSION_METHOD COMPRESS_DEFLATE
#define DEFAULT_COMPRESSION_LEVEL Z_DEFAULT_COMPRESSION
#define DEFAULT_SPLIT_SIZE (2*1024*1024*1024)  // 2GB

// 文件权限掩码
#define DIR_PERM (S_IRWXU | S_IRWXG | S_IRWXO)  // 目录权限
#define FILE_PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)  // 文件权限

//### 2. 压缩算法枚举

typedef enum {
    COMPRESS_STORE = 0,    // 无压缩
    COMPRESS_DEFLATE = 8,  // DEFLATE算法
    COMPRESS_BZIP2 = 12,   // BZIP2算法 (需要额外库)
    COMPRESS_LZMA = 14     // LZMA算法 (需要额外库)
} compression_method_t;


//### 3. ZIP文件头结构

#pragma pack(push, 1)
typedef struct {
    uint32_t signature;          // 0x04034b50
    uint16_t version_needed;
    uint16_t flags;
    uint16_t compression;
    uint16_t mod_time;
    uint16_t mod_date;
    uint32_t crc32;
    uint32_t compressed_size;
    uint32_t uncompressed_size;
    uint16_t filename_len;
    uint16_t extra_len;
} local_header_t;

typedef struct {
    uint32_t signature;          // 0x02014b50
    uint16_t version_made;
    uint16_t version_needed;
    uint16_t flags;
    uint16_t compression;
    uint16_t mod_time;
    uint16_t mod_date;
    uint32_t crc32;
    uint32_t compressed_size;
    uint32_t uncompressed_size;
    uint16_t filename_len;
    uint16_t extra_len;
    uint16_t comment_len;
    uint16_t disk_num;
    uint16_t internal_attr;
    uint32_t external_attr;
    uint32_t header_offset;
} central_dir_header_t;

typedef struct {
    uint32_t signature;          // 0x06054b50
    uint16_t disk_num;
    uint16_t dir_start_disk;
    uint16_t entries_on_disk;
    uint16_t total_entries;
    uint32_t dir_size;
    uint32_t dir_offset;
    uint16_t comment_len;
} end_central_dir_t;
#pragma pack(pop)

//1. ZIP文件条目结构 (zip_file_entry_t)
typedef struct {
    // 文件基本信息
    char *filename;                // 存档中的文件名(含路径)
    uint32_t crc;                  // CRC32校验和
    uint32_t comp_size;            // 压缩后大小
    uint32_t uncomp_size;          // 原始大小
    
    // 压缩参数
    compression_method_t method;    // 使用的压缩算法
    int compression_level;         // 压缩级别
    
    // 时间信息
    uint16_t mod_time;             // DOS格式修改时间
    uint16_t mod_date;             // DOS格式修改日期
    
    // 数据指针
    void *data;                    // 压缩后的数据(如果已加载到内存)
    
    // ZIP文件结构
    uint32_t header_offset;        // 本地文件头在ZIP中的偏移
    int is_directory;              // 是否为目录条目
} zip_file_entry_t;


//2. ZIP文件结构 (zip_file_t)
typedef struct {
    // 文件流
    FILE *fp;                      // ZIP文件句柄
    
    // 条目管理
    zip_file_entry_t *entries;     // 条目数组
    int count;                     // 当前条目数量
    int capacity;                  // 数组容量
    
    // 全局属性
    compression_method_t default_method; // 默认压缩算法
    int default_level;             // 默认压缩级别
    
    // 状态标志
    int is_modified;               // 是否有未写入的更改
    int is_open;                   // 是否已打开
    
    // 中央目录缓存
    long cd_offset;                // 中央目录起始位置
} zip_file_t;
//3. 程序配置结构 (program_options_t)
typedef struct {
    // 压缩参数
    compression_method_t method;    // 压缩算法
    int level;                     // 压缩级别 (1-9)
    
    // 输入输出
    char output_file[PATH_MAX];    // 输出ZIP文件名
    char **input_patterns;         // 输入模式数组
    int input_count;               // 输入模式数量
    
    // 行为选项
    int recursive;                 // 是否递归处理目录
    int verbose;                   // 是否显示详细信息
    int follow_symlinks;           // 是否跟随符号链接
    int preserve_permissions;      // 是否保留文件权限
    int include_hidden;            // 是否包含隐藏文件
    
    // 高级选项
    int split_volume;              // 是否分卷压缩
    size_t max_volume_size;        // 最大分卷大小
    int encryption_method;         // 加密算法 (0=无加密)
    char password[256];            // 加密密码
    
    // 通配符选项
    int case_sensitive;            // 通配符是否大小写敏感
    int extended_glob;             // 是否启用扩展通配符(如**)
    
    // 进度回调
    void (*progress_callback)(int percent, const char *message); // 进度回调函数
    void *callback_data;           // 回调用户数据
} program_options_t;

//### 4. 核心函数实现

//#### 压缩算法选择

int get_compression_level(compression_method_t method) {
    switch(method) {
        case COMPRESS_DEFLATE:
            return Z_DEFAULT_COMPRESSION;
        case COMPRESS_BZIP2:
            return 6; // 默认bzip2级别
        default:
            return 0;
    }
}


/**
 * 初始化ZIP文件结构
 * @param zip: 待初始化的结构
 * @param fp: 已打开的文件句柄(调用者负责打开文件)
 * @return 0=成功, -1=失败
 */
int zip_init(zip_file_t *zip, FILE *fp) {
    if (!zip || !fp) {
        fprintf(stderr, "错误: 参数不能为NULL\n");
        return -1;
    }

    // 清零整个结构
    memset(zip, 0, sizeof(zip_file_t));

    // 设置初始值
    zip->fp = fp;
    zip->is_open = 1;
    zip->default_method = COMPRESS_DEFLATE;
    zip->default_level = Z_DEFAULT_COMPRESSION;
    zip->capacity = ZIP_ENTRY_INIT_CAPACITY;
    
    // 分配初始条目数组
    zip->entries = calloc(zip->capacity, sizeof(zip_file_entry_t));
    if (!zip->entries) {
        fprintf(stderr, "错误: 内存不足\n");
        return -1;
    }

    return 0;
}
/**
 * 清理ZIP文件资源
 * @param zip: 已初始化的ZIP结构
 */
void zip_cleanup(zip_file_t *zip) {
    if (!zip) return;

    // 释放条目资源
    for (int i = 0; i < zip->count; i++) {
        free(zip->entries[i].filename);
        free(zip->entries[i].data);
    }
    free(zip->entries);

    // 重置结构
    memset(zip, 0, sizeof(zip_file_t)); // 包含将 is_open 设为 0
}


/**
 * 压缩文件数据核心函数
 * @param source: 源文件句柄
 * @param compressed_data: 输出压缩数据指针
 * @param compressed_size: 输出压缩后大小
 * @param method: 压缩算法
 * @param level: 压缩级别
 * @return 1=成功, 0=失败
 */
int compress_file_data(FILE *source, void **compressed_data, uint32_t *compressed_size, //size_t *compressed_size
                      compression_method_t method, int level) {
    // 1. 获取源文件大小
    long src_pos = ftell(source);
    fseek(source, 0, SEEK_END);
    size_t src_size = ftell(source);
    fseek(source, src_pos, SEEK_SET);

    if (src_size == 0) {
        *compressed_data = NULL;
        *compressed_size = 0;
        return 1;
    }

    // 2. 处理不同压缩算法
    switch (method) {
        case COMPRESS_STORE: {
            // 无压缩
            *compressed_data = malloc(src_size);
            *compressed_size = src_size;
            size_t read = fread(*compressed_data, 1, src_size, source);
            return read == src_size;
        }

        case COMPRESS_DEFLATE: {
            // DEFLATE压缩
            z_stream stream;
            stream.zalloc = Z_NULL;
            stream.zfree = Z_NULL;
            stream.opaque = Z_NULL;

            // 初始化压缩流
            int ret = deflateInit2(&stream, level, Z_DEFLATED,
                                  -15, 8, Z_DEFAULT_STRATEGY); // -15 = 16+8,启用zlib头
            if (ret != Z_OK) return 0;

            // 输入数据
            stream.next_in = (Bytef *)malloc(src_size);
            stream.avail_in = fread(stream.next_in, 1, src_size, source);
            if (stream.avail_in != src_size) {
                free(stream.next_in);
                deflateEnd(&stream);
                return 0;
            }

            // 输出缓冲区
            size_t comp_size = (size_t)(src_size * 1.1 + 12);
            *compressed_data = malloc(comp_size);
            stream.next_out = *compressed_data;
            stream.avail_out = comp_size;

            // 执行压缩
            ret = deflate(&stream, Z_FINISH);
            *compressed_size = stream.total_out;
            //fprintf(stderr, "执行压缩完成%ld\n", stream.total_out);
            // 清理
            //free(stream.next_in);
            //deflateEnd(&stream);
            //fprintf(stderr, "执行压缩清理完成\n");
            if (ret != Z_STREAM_END) {
                free(*compressed_data);
                return 0;
            }
            return 1;
        }

        case COMPRESS_BZIP2: {
#ifdef HAVE_LIBBZ2
            // BZIP2压缩实现 (需要链接libbz2)
            // 这里仅留空实现,实际使用时需要包含bzlib.h
            fprintf(stderr, "错误: BZIP2压缩未启用\n");
            return 0;
#else
            fprintf(stderr, "错误: BZIP2压缩不支持\n");
            return 0;
#endif
        }

        case COMPRESS_LZMA: {
#ifdef HAVE_LIBLZMA
            // LZMA压缩实现 (需要链接liblzma)
            fprintf(stderr, "错误: LZMA压缩未启用\n");
            return 0;
#else
            fprintf(stderr, "错误: LZMA压缩不支持\n");
            return 0;
#endif
        }

        default:
            fprintf(stderr, "错误: 不支持的压缩算法 %d\n", method);
            return 0;
    }
}

void write_local_header(FILE *zip, const char *filename, uint32_t crc, 
                       uint32_t comp_size, uint32_t uncomp_size, 
                       compression_method_t method) {
    local_header_t header = {
        .signature = 0x04034b50,
        .version_needed = 20,
        .compression = method,
        .crc32 = crc,
        .compressed_size = comp_size,
        .uncompressed_size = uncomp_size,
        .filename_len = strlen(filename),
        .extra_len = 0
    };

    // 设置修改时间
    time_t now = time(NULL);
    struct tm *tm = localtime(&now);
    header.mod_time = (tm->tm_hour << 11) | (tm->tm_min << 5) | (tm->tm_sec >> 1);
    header.mod_date = ((tm->tm_year + 1900 - 1980) << 9) | ((tm->tm_mon + 1) << 5) | tm->tm_mday;

    fwrite(&header, sizeof(header), 1, zip);
    fwrite(filename, 1, strlen(filename), zip);
}

void write_central_directory(FILE *zip, const zip_file_entry_t *entries, int count) {
    uint32_t cd_offset = ftell(zip);
    uint32_t cd_size = 0;

    for (int i = 0; i < count; i++) {
        central_dir_header_t header = {
            .signature = 0x02014b50,
            .version_made = 20,
            .version_needed = 20,
            .compression = entries[i].method,
            .crc32 = entries[i].crc,
            .compressed_size = entries[i].comp_size,
            .uncompressed_size = entries[i].uncomp_size,
            .filename_len = strlen(entries[i].filename),
            .extra_len = 0,
            .comment_len = 0,
            .disk_num = 0,
            .internal_attr = 0,
            .external_attr = 0x81a40000, // 默认文件属性
            .header_offset = entries[i].header_offset
        };

        header.mod_time = entries[i].mod_time;
        header.mod_date = entries[i].mod_date;

        fwrite(&header, sizeof(header), 1, zip);
        fwrite(entries[i].filename, 1, strlen(entries[i].filename), zip);
        cd_size += sizeof(header) + strlen(entries[i].filename);
    }

    end_central_dir_t end = {
        .signature = 0x06054b50,
        .disk_num = 0,
        .dir_start_disk = 0,
        .entries_on_disk = count,
        .total_entries = count,
        .dir_size = cd_size,
        .dir_offset = cd_offset,
        .comment_len = 0
    };

    fwrite(&end, sizeof(end), 1, zip);
}

/**
 * 将单个文件添加到ZIP存档
 * @param zip: ZIP文件结构指针
 * @param file_path: 要添加的本地文件路径
 * @param archive_name: 在ZIP中的名称(含路径)
 * @param method: 压缩算法
 * @param level: 压缩级别
 * @return 0=成功, -1=失败
 */
int add_file_to_zip(zip_file_t *zip, const char *file_path, 
                   const char *archive_name,
                   compression_method_t method, int level) {
    // 1. 输入验证
    if (!zip || !file_path || !archive_name) {
        fprintf(stderr, "错误: 参数不能为NULL\n");
        return -1;
    }
/*
    if (!zip->is_open) {
        fprintf(stderr, "错误: ZIP文件未打开\n");
        return -1;
    }
*/
    // 2. 检查ZIP是否初始化(新增关键检查)
    if (!zip->fp || !zip->is_open) {  // 同时检查文件句柄和标志
        fprintf(stderr, "错误: ZIP文件未正确初始化或已关闭\n");
        return -1;
    }
    // 2. 打开源文件
    FILE *src = fopen(file_path, "rb");
    if (!src) {
        fprintf(stderr, "警告: 无法打开文件 %s (跳过)\n", file_path);
        return -1;
    }

    // 3. 获取文件状态
    struct stat st;
    if (fstat(fileno(src), &st) == -1) {
        fprintf(stderr, "警告: 无法获取文件状态 %s (跳过)\n", file_path);
        fclose(src);
        return -1;
    }

    // 4. 初始化条目
    zip_file_entry_t entry = {0};
    entry.filename = strdup(archive_name);
    entry.method = (method == COMPRESS_STORE && S_ISDIR(st.st_mode)) ? 
                   COMPRESS_STORE : method;  // 目录强制使用STORE
    entry.compression_level = level;
    entry.uncomp_size = S_ISDIR(st.st_mode) ? 0 : st.st_size;
    entry.is_directory = S_ISDIR(st.st_mode);
    
    // 设置DOS格式时间
    struct tm *tm = localtime(&st.st_mtime);
    entry.mod_time = (tm->tm_hour << 11) | (tm->tm_min << 5) | (tm->tm_sec >> 1);
    entry.mod_date = ((tm->tm_year + 1900 - 1980) << 9) | ((tm->tm_mon + 1) << 5) | tm->tm_mday;

    // 5. 计算CRC32 (先于压缩计算)
    if (!entry.is_directory) {
        uint32_t crc = crc32(0L, Z_NULL, 0);
        unsigned char buffer[8192];
        size_t bytes_read;
        
        // 重置文件指针
        rewind(src);
        while ((bytes_read = fread(buffer, 1, sizeof(buffer), src)) > 0) {
            crc = crc32(crc, buffer, bytes_read);
        }
        entry.crc = crc;
    } else {
        entry.crc = 0;
    }
    //fprintf(stderr, "计算CRC32 (先于压缩计算)完成\n");
    // 6. 压缩数据
    if (!entry.is_directory && entry.uncomp_size > 0) {
        // 重置文件指针准备读取
        rewind(src);
        
        // 压缩数据
        if (!compress_file_data(src, &entry.data, &entry.comp_size, 
                               entry.method, entry.compression_level)) {
            fprintf(stderr, "警告: 压缩文件 %s 失败 (跳过)\n", file_path);
            free(entry.filename);
            fclose(src);
            return -1;
        }
    } else {
        entry.data = NULL;
        entry.comp_size = 0;
    }
    //fprintf(stderr, "压缩数据完成\n");
    // 7. 写入本地文件头
    entry.header_offset = ftell(zip->fp);
    write_local_header(zip->fp, entry.filename, entry.crc, 
                      entry.comp_size, entry.uncomp_size, entry.method);
    //fprintf(stderr, "写入本地文件头\n");
    // 8. 写入文件数据
    if (entry.comp_size > 0) {
        size_t written = fwrite(entry.data, 1, entry.comp_size, zip->fp);
        if (written != entry.comp_size) {
            fprintf(stderr, "错误: 写入文件数据失败 %s\n", file_path);
            free(entry.data);
            free(entry.filename);
            fclose(src);
            return -1;
        }
        // 释放压缩数据内存
        free(entry.data);
        entry.data = NULL;
    }
    fprintf(stderr, "写入%s文件数据\n", entry.filename);
    // 9. 添加到条目数组
    if (zip->count >= zip->capacity) {
        // 数组扩容
        zip->capacity = zip->capacity > 0 ? 
                       (int)(zip->capacity * ZIP_ENTRY_GROWTH_FACTOR) : 
                       ZIP_ENTRY_INIT_CAPACITY;
        zip_file_entry_t *new_entries = realloc(zip->entries, 
                                               zip->capacity * sizeof(zip_file_entry_t));
        if (!new_entries) {
            fprintf(stderr, "错误: 内存不足\n");
            free(entry.filename);
            fclose(src);
            return -1;
        }
        zip->entries = new_entries;
    }

    // 复制条目到数组(仅元数据)
    zip->entries[zip->count] = entry;
    zip->count++;

    // 10. 清理资源
    fclose(src);
    
    // 11. 设置修改标志
    zip->is_modified = 1;

    // 12. 可选:显示进度
    /*
    if (zip->progress_callback) {
        char msg[256];
        snprintf(msg, sizeof(msg), "已添加: %s", archive_name);
        zip->progress_callback((zip->count * 100) / zip->capacity, msg);
    }
    */
    return 0;
}
/**
 * 添加目录条目到ZIP
 * @param zip: ZIP文件结构
 * @param dir_path: 目录在ZIP中的路径
 */
void add_dir_entry(zip_file_t *zip, const char *dir_path) {
    // 确保目录路径以'/'结尾
    char dir_name[PATH_MAX];
    snprintf(dir_name, sizeof(dir_name), "%s%s", 
             dir_path, (dir_path[strlen(dir_path)-1] != '/') ? "/" : "");

    add_file_to_zip(zip, "/dev/null", dir_name, COMPRESS_STORE, 0);
}


//#### 递归目录遍历

void add_directory_to_zip(zip_file_t *zip, const char *path, const char *base_path, 
                         compression_method_t method, int compression_level) {
    DIR *dir = opendir(path);
    if (!dir) {
        perror("无法打开目录");
        return;
    }
    //fprintf(stderr, "写入%s目录数据\n", path);
    struct dirent *entry;
    while ((entry = readdir(dir)) != NULL) {
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
            continue;

        char full_path[PATH_MAX];
        snprintf(full_path, sizeof(full_path), "%s/%s", path, entry->d_name);

        char archive_path[PATH_MAX];
        snprintf(archive_path, sizeof(archive_path), "%s/%s", 
                base_path ? base_path : "", entry->d_name);

        struct stat st;
        if (lstat(full_path, &st) == -1) {
            perror("无法获取文件状态");
            continue;
        }

        if (S_ISDIR(st.st_mode)) {
            // 添加目录条目
            //add_dir_entry(zip, archive_path);
            // 递归处理子目录
            add_directory_to_zip(zip, full_path, archive_path, method, compression_level);
        } else if (S_ISREG(st.st_mode)) {
        	//fprintf(stderr, "添加常规文件%s\n", archive_path+1); 
            add_file_to_zip(zip, full_path, archive_path+1, method, compression_level);  //archive_path+1去掉多余的/前缀
        }
    }

    closedir(dir);
}


//#### 通配符匹配

int is_match(const char *pattern, const char *string) {
    return fnmatch(pattern, string, FNM_PATHNAME) == 0;
}

void add_matching_files(zip_file_t *zip, const char *dir_path, const char *pattern,
                       compression_method_t method, int compression_level) {
    DIR *dir = opendir(dir_path);
    if (!dir) return;

    struct dirent *entry;
    while ((entry = readdir(dir)) != NULL) {
        char full_path[PATH_MAX];
        snprintf(full_path, sizeof(full_path), "%s/%s", dir_path, entry->d_name);

        struct stat st;
        if (lstat(full_path, &st) == -1) continue;

        if (S_ISREG(st.st_mode) && is_match(pattern, entry->d_name)) {
            add_file_to_zip(zip, full_path, entry->d_name, method, compression_level);
        } else if (S_ISDIR(st.st_mode)) {
            char new_pattern[PATH_MAX];
            snprintf(new_pattern, sizeof(new_pattern), "%s/%s", entry->d_name, pattern);
            if (is_match(new_pattern, "*")) { // 如果模式包含该目录
                add_matching_files(zip, full_path, pattern, method, compression_level);
            }
        }
    }

    closedir(dir);
}

//### 5. 主程序逻辑

//#### 命令行参数解析

int parse_args(int argc, char *argv[], program_options_t *opts) {
    static struct option long_options[] = {
        {"algorithm", required_argument, 0, 'a'},
        {"level", required_argument, 0, 'l'},
        {"output", required_argument, 0, 'o'},
        {0, 0, 0, 0}
    };

    int opt;
    while ((opt = getopt_long(argc, argv, "a:l:o:", long_options, NULL)) != -1) {
        switch(opt) {
            case 'a':
                if (strcmp(optarg, "deflate") == 0) opts->method = COMPRESS_DEFLATE;
                else if (strcmp(optarg, "store") == 0) opts->method = COMPRESS_STORE;
                else if (strcmp(optarg, "bzip2") == 0) opts->method = COMPRESS_BZIP2;
                else if (strcmp(optarg, "lzma") == 0) opts->method = COMPRESS_LZMA;
                break;
            case 'l':
                opts->level = atoi(optarg);
                break;
            case 'o':
                strncpy(opts->output_file, optarg, sizeof(opts->output_file));
                break;
            default:
                return -1;
        }
    }
    
    opts->input_count = argc - optind;
    opts->input_patterns = &argv[optind];
    return 0;
}


//#### 主流程

int main(int argc, char *argv[]) {
    program_options_t opts = {
        .method = COMPRESS_DEFLATE,
        .level = Z_DEFAULT_COMPRESSION,
        .output_file = "output.zip"
    };

    if (parse_args(argc, argv, &opts) != 0) {
        fprintf(stderr, "用法: %s [选项] <文件/目录/通配符...>\n", argv[0]);
        return 1;
    }

    FILE *zip = fopen(opts.output_file, "wb");
    if (!zip) {
        perror("无法创建ZIP文件");
        return 1;
    }
/*
    zip_file_t archive = {
        .fp = zip,
        .entries = NULL,
        .count = 0,
        .capacity = 0
    };
*/
    // "初始化ZIP结构出错");"
    zip_file_t archive = {0}; // 清零结构
    if (zip_init(&archive, zip) != 0) {
    	perror("初始化ZIP结构出错");
        fclose(zip);
        return 1;
    }
    // 处理每个输入模式
    for (int i = 0; i < opts.input_count; i++) {
        struct stat st;
        if (lstat(opts.input_patterns[i], &st) == -1) {
            // 可能是通配符
            char *dir = ".";
            char pattern[PATH_MAX];
            char *slash = strrchr(opts.input_patterns[i], '/');
            if (slash) {
                *slash = '\0';
                if (strlen(opts.input_patterns[i]) > 0) dir = opts.input_patterns[i];
                strcpy(pattern, slash + 1);
            } else {
                strcpy(pattern, opts.input_patterns[i]);
            }

            add_matching_files(&archive, dir, pattern, opts.method, opts.level);
        } else if (S_ISDIR(st.st_mode)) {
            add_directory_to_zip(&archive, opts.input_patterns[i], NULL, 
                               opts.method, opts.level);
        } else {
            add_file_to_zip(&archive, opts.input_patterns[i], 
                           basename(opts.input_patterns[i]), opts.method, opts.level);
        }
    }

    // 写入中央目录和结束记录
    write_central_directory(zip, archive.entries, archive.count);

    // 清理资源
 /*
    for (int i = 0; i < archive.count; i++) {
        free(archive.entries[i].filename);
        free(archive.entries[i].data);
    }
    free(archive.entries);
 */
    fclose(zip);

    printf("成功创建ZIP文件: %s (%d个条目)\n", opts.output_file, archive.count);
    return 0;
}

编译与使用

编译指令

bash 复制代码
gcc -o myzip myzip.c -lz 

使用示例

  1. 压缩目录:

    bash 复制代码
    ./myzip -a deflate -l 6 -o backup.zip /path/to/directory/
  2. 使用通配符:

    bash 复制代码
    ./myzip -a store *.c *.h
  3. 混合使用:

    bash 复制代码
    ./myzip -o project.zip src/*.c include/*.h docs/
  4. 选择不同算法:

    bash 复制代码
    ./myzip -a bzip2 -l 9 -o data.zip *.csv

扩展功能

1. 多压缩算法支持

  • 通过-a/--algorithm参数选择压缩算法
  • 支持STORE(无压缩)、DEFLATE、BZIP2、LZMA等

2. 压缩级别控制

  • 通过-l/--level参数设置压缩级别(1-9)

3. 递归目录处理

  • 自动遍历子目录结构
  • 保留目录层级关系

4. 通配符支持

  • 支持*?通配符
  • 支持**递归匹配(可选扩展)

5. 错误处理

  • 文件不存在时跳过
  • 权限错误提示
  • 磁盘空间检查

注意事项

  1. 需要链接zlib库(-lz)
  2. 对于BZIP2/LZMA需要额外库支持
  3. 大文件处理需要考虑内存使用
  4. 文件名编码处理(当前为UTF-8)
  5. 符号链接处理策略(当前跳过)

这个实现提供了一个功能完整的ZIP压缩工具框架,可以根据需要进一步扩展功能,如加密、分卷压缩、进度显示等。

注\] 完整实现还需要添加错误恢复、内存管理优化等细节。建议参考Info-ZIP或ZIP标准文档获取更详细的格式规范^[1](#1)^^[2](#2)^。 *** ** * ** *** 1. APPNOTE.TXT - .ZIP File Format Specification: https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT [↩︎](#↩︎) 2. zlib官网: https://zlib.net/ [↩︎](#↩︎)

相关推荐
AngelPP2 小时前
OpenClaw 架构深度解析:如何把 AI 助手搬到你的个人设备上
人工智能
宅小年2 小时前
Claude Code 换成了Kimi K2.5后,我再也回不去了
人工智能·ai编程·claude
九狼2 小时前
Flutter URL Scheme 跨平台跳转
人工智能·flutter·github
ZFSS2 小时前
Kimi Chat Completion API 申请及使用
前端·人工智能
天翼云开发者社区3 小时前
春节复工福利就位!天翼云息壤2500万Tokens免费送,全品类大模型一键畅玩!
人工智能·算力服务·息壤
知识浅谈3 小时前
教你如何用 Gemini 将课本图片一键转为精美 PPT
人工智能
Ray Liang4 小时前
被低估的量化版模型,小身材也能干大事
人工智能·ai·ai助手·mindx
颜酱5 小时前
单调栈:从模板到实战
javascript·后端·算法
shengjk15 小时前
NanoClaw 深度剖析:一个"AI 原生"架构的个人助手是如何运转的?
人工智能