利用美团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/ [↩︎](#↩︎)

相关推荐
GUPAOAI3 小时前
阅兵背后的科技:战场上的目标检测与无人机巡检
人工智能·科技·深度学习·目标检测·计算机视觉·ai·无人机
正在走向自律3 小时前
解锁WebRTC在数字人领域的无限潜能
人工智能·python·llm·webrtc·数字人·微软autogen·实时语音交互
hansang_IR3 小时前
【线性代数基础 | 那忘算9】基尔霍夫(拉普拉斯)矩阵 & 矩阵—树定理证明 [详细推导]
c++·笔记·线性代数·算法·矩阵·矩阵树定理·基尔霍夫矩阵
观察猿3 小时前
亚马逊流量突围:如何用智能化关键词运营找到更多高转化机会?
大数据·人工智能·产品运营
lingchen19063 小时前
MATLAB矩阵及其运算(三)矩阵的创建
算法·matlab·矩阵
MatrixOrigin3 小时前
以数生智,以智驭数:GenAI新常态下的企业数据之道 | 矩阵起源产品发布会重磅启幕
大数据·人工智能·ai
whatever who cares3 小时前
Android/Java 异常捕获
android·java·开发语言
小妖同学学AI3 小时前
百度发布Comate AI IDE,我要把Cursor卸载了!
ide·人工智能·百度·ai编程
林森见鹿4 小时前
AI编码生产力翻倍:你必须掌握的沟通、流程、工具与安全心法
人工智能