一、Zlib 库介绍

Zlib 是一个广泛使用的、开源的数据压缩库,它实现了 DEFLATE 压缩算法,提供了高效、可靠的数据压缩和解压功能。Zlib 是一个用于数据压缩的软件库,由 Jean-loup Gailly 和 Mark Adler 创建。它实现了 DEFLATE 压缩算法,该算法结合了 LZ77 算法和霍夫曼编码。

核心特性
  • 无损压缩:解压后的数据与原始数据完全相同
  • 高性能:压缩和解压速度都很快
  • 内存效率:占用内存小,适合嵌入式系统
  • 跨平台:支持几乎所有操作系统和编译器
  • 开源免费:使用 zlib 许可证,可自由用于商业项目

二、boost库编译

下载Zlib源码包:https://www.zlib.net/zlib131.zip

直接解压缩就行了,找到路径zlib-1.3.1\contrib\vstudio\vc14里面的zlibvc.sln

在这里插入图片描述

直接使用Visual Studio打开然后编译就行

在这里插入图片描述
在这里插入图片描述
然后我们就可以在项目中使用zlib库了,如果需要zip压缩的话,找到zlib-1.3.1\contrib文件夹下minizip,在vs中创建一个项目将该文件夹下的文件添加到项目中,修改配置类型为lib,直接编译即可
在这里插入图片描述
然后我们创建一个项目zlib_zip,将头文件添加到项目中
在这里插入图片描述

然后将刚刚编译好的库链接到项目中。

三、代码实现

首先,我们需要添加所需要的文件
// 需要的库和头文件
#include "minizip/zip.h"    // 压缩功能
#include "minizip/unzip.h"  // 解压功能
#include <direct.h>         // 目录操作(Windows)
然后我们需要,目录检测与创建
// 使用标准库实现跨平台兼容性
bool directoryExists(const std::string& path) {
    struct stat info;
    return stat(path.c_str(), &info) == 0 && (info.st_mode & S_IFDIR);
}
// 核心压缩流程
zipFile zf = zipOpen(zipFilename.c_str(), APPEND_STATUS_CREATE);
// ... 文件处理逻辑
zipClose(zf, nullptr);
zip工具类
class ZipUtility {
public:
    // 创建标准 zip 文件(只支持文件,不支持目录)
    static bool createZip(const std::string& zipFilename,
        const std::vector<std::string>& filesToAdd) {
        zipFile zf = zipOpen(zipFilename.c_str(), APPEND_STATUS_CREATE);
        if (!zf) {
            std::cerr << "无法创建 zip 文件: " << zipFilename << std::endl;
            return false;
        }

        bool success = true;

        for (const auto& filepath : filesToAdd) {
            std::cout << "添加文件到 zip: " << filepath << std::endl;

            // 打开要添加的文件
            FILE* file = fopen(filepath.c_str(), "rb");
            if (!file) {
                std::cerr << "无法打开文件: " << filepath << std::endl;
                success = false;
                continue;
            }

            // 获取文件大小
            fseek(file, 0, SEEK_END);
            long fileSize = ftell(file);
            fseek(file, 0, SEEK_SET);

            // 读取文件内容
            char* fileData = new char[fileSize];
            fread(fileData, 1, fileSize, file);
            fclose(file);

            // 设置 zip 文件信息
            zip_fileinfo zi = { 0 };

            // 提取文件名(不带路径)
            std::string filename = filepath;
            size_t lastSlash = filepath.find_last_of("/\\");
            if (lastSlash != std::string::npos) {
                filename = filepath.substr(lastSlash + 1);
            }

            // 在 zip 文件中打开一个新文件
            int err = zipOpenNewFileInZip(zf, filename.c_str(), &zi,
                nullptr, 0, nullptr, 0, nullptr,
                Z_DEFLATED, Z_DEFAULT_COMPRESSION);

            if (err != ZIP_OK) {
                std::cerr << "无法在 zip 中创建文件条目: " << filename << std::endl;
                delete[] fileData;
                success = false;
                continue;
            }

            // 写入文件数据
            err = zipWriteInFileInZip(zf, fileData, fileSize);
            if (err != ZIP_OK) {
                std::cerr << "写入 zip 文件失败: " << filename << std::endl;
                delete[] fileData;
                zipCloseFileInZip(zf);
                success = false;
                continue;
            }

            // 关闭 zip 中的文件
            zipCloseFileInZip(zf);
            delete[] fileData;
        }

        // 关闭 zip 文件
        zipClose(zf, nullptr);

        if (success) {
            std::cout << "成功创建 zip 文件: " << zipFilename << std::endl;
        }
        return success;
    }

    // 解压标准 zip 文件
    static bool extractZip(const std::string& zipFilename,
        const std::string& outputDir = "") {
        // 打开 zip 文件
        unzFile uf = unzOpen(zipFilename.c_str());
        if (!uf) {
            std::cerr << "无法打开 zip 文件: " << zipFilename << std::endl;
            return false;
        }

        // 创建输出目录(如果不存在)
        if (!outputDir.empty() && !directoryExists(outputDir)) {
            createDirectory(outputDir);
        }

        unz_global_info gi;
        if (unzGetGlobalInfo(uf, &gi) != UNZ_OK) {
            std::cerr << "无法读取 zip 文件信息" << std::endl;
            unzClose(uf);
            return false;
        }

        std::cout << "zip 文件包含 " << gi.number_entry << " 个文件" << std::endl;

        bool success = true;

        // 遍历所有文件
        for (int i = 0; i < gi.number_entry; i++) {
            unz_file_info file_info;
            char filename[256];
            if (unzGetCurrentFileInfo(uf, &file_info, filename,
                sizeof(filename), nullptr, 0, nullptr, 0) != UNZ_OK) {
                std::cerr << "无法读取文件信息" << std::endl;
                success = false;
                continue;
            }

            std::string outputFilename = outputDir + filename;
            std::cout << "解压: " << filename << " -> " << outputFilename << std::endl;

            // 打开当前文件进行解压
            if (unzOpenCurrentFile(uf) != UNZ_OK) {
                std::cerr << "无法打开 zip 中的文件: " << filename << std::endl;
                success = false;
                continue;
            }

            // 创建输出文件
            FILE* outFile = fopen(outputFilename.c_str(), "wb");
            if (!outFile) {
                std::cerr << "无法创建输出文件: " << outputFilename << std::endl;
                unzCloseCurrentFile(uf);
                success = false;
                continue;
            }

            // 读取并写入文件数据
            char buffer[8192];
            int bytesRead;
            while ((bytesRead = unzReadCurrentFile(uf, buffer, sizeof(buffer))) > 0) {
                fwrite(buffer, 1, bytesRead, outFile);
            }

            fclose(outFile);
            unzCloseCurrentFile(uf);

            // 移动到下一个文件
            if (i < gi.number_entry - 1) {
                if (unzGoToNextFile(uf) != UNZ_OK) {
                    std::cerr << "无法移动到下一个文件" << std::endl;
                    success = false;
                    break;
                }
            }
        }

        unzClose(uf);
        if (success) {
            std::cout << "解压完成" << std::endl;
        }
        return success;
    }
};
完整代码如下
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <cstring>
#include <algorithm>
#include <sys/stat.h>
#include "minizip/zip.h"
#include "minizip/unzip.h"
#include <direct.h>

// 简单的目录存在检查(跨平台)
bool directoryExists(const std::string& path) {
    struct stat info;
    return stat(path.c_str(), &info) == 0 && (info.st_mode & S_IFDIR);
}

// 创建目录(跨平台)
bool createDirectory(const std::string& path) {
#ifdef _WIN32
    return _mkdir(path.c_str()) == 0;
#else
    return mkdir(path.c_str(), 0755) == 0;
#endif
}

class ZipUtility {
public:
    // 创建标准 zip 文件(只支持文件,不支持目录)
    static bool createZip(const std::string& zipFilename,
        const std::vector<std::string>& filesToAdd) {
        zipFile zf = zipOpen(zipFilename.c_str(), APPEND_STATUS_CREATE);
        if (!zf) {
            std::cerr << "无法创建 zip 文件: " << zipFilename << std::endl;
            return false;
        }

        bool success = true;

        for (const auto& filepath : filesToAdd) {
            std::cout << "添加文件到 zip: " << filepath << std::endl;

            // 打开要添加的文件
            FILE* file = fopen(filepath.c_str(), "rb");
            if (!file) {
                std::cerr << "无法打开文件: " << filepath << std::endl;
                success = false;
                continue;
            }

            // 获取文件大小
            fseek(file, 0, SEEK_END);
            long fileSize = ftell(file);
            fseek(file, 0, SEEK_SET);

            // 读取文件内容
            char* fileData = new char[fileSize];
            fread(fileData, 1, fileSize, file);
            fclose(file);

            // 设置 zip 文件信息
            zip_fileinfo zi = { 0 };

            // 提取文件名(不带路径)
            std::string filename = filepath;
            size_t lastSlash = filepath.find_last_of("/\\");
            if (lastSlash != std::string::npos) {
                filename = filepath.substr(lastSlash + 1);
            }

            // 在 zip 文件中打开一个新文件
            int err = zipOpenNewFileInZip(zf, filename.c_str(), &zi,
                nullptr, 0, nullptr, 0, nullptr,
                Z_DEFLATED, Z_DEFAULT_COMPRESSION);

            if (err != ZIP_OK) {
                std::cerr << "无法在 zip 中创建文件条目: " << filename << std::endl;
                delete[] fileData;
                success = false;
                continue;
            }

            // 写入文件数据
            err = zipWriteInFileInZip(zf, fileData, fileSize);
            if (err != ZIP_OK) {
                std::cerr << "写入 zip 文件失败: " << filename << std::endl;
                delete[] fileData;
                zipCloseFileInZip(zf);
                success = false;
                continue;
            }

            // 关闭 zip 中的文件
            zipCloseFileInZip(zf);
            delete[] fileData;
        }

        // 关闭 zip 文件
        zipClose(zf, nullptr);

        if (success) {
            std::cout << "成功创建 zip 文件: " << zipFilename << std::endl;
        }
        return success;
    }

    // 解压标准 zip 文件
    static bool extractZip(const std::string& zipFilename,
        const std::string& outputDir = "") {
        // 打开 zip 文件
        unzFile uf = unzOpen(zipFilename.c_str());
        if (!uf) {
            std::cerr << "无法打开 zip 文件: " << zipFilename << std::endl;
            return false;
        }

        // 创建输出目录(如果不存在)
        if (!outputDir.empty() && !directoryExists(outputDir)) {
            createDirectory(outputDir);
        }

        unz_global_info gi;
        if (unzGetGlobalInfo(uf, &gi) != UNZ_OK) {
            std::cerr << "无法读取 zip 文件信息" << std::endl;
            unzClose(uf);
            return false;
        }

        std::cout << "zip 文件包含 " << gi.number_entry << " 个文件" << std::endl;

        bool success = true;

        // 遍历所有文件
        for (int i = 0; i < gi.number_entry; i++) {
            unz_file_info file_info;
            char filename[256];
            if (unzGetCurrentFileInfo(uf, &file_info, filename,
                sizeof(filename), nullptr, 0, nullptr, 0) != UNZ_OK) {
                std::cerr << "无法读取文件信息" << std::endl;
                success = false;
                continue;
            }

            std::string outputFilename = outputDir + filename;
            std::cout << "解压: " << filename << " -> " << outputFilename << std::endl;

            // 打开当前文件进行解压
            if (unzOpenCurrentFile(uf) != UNZ_OK) {
                std::cerr << "无法打开 zip 中的文件: " << filename << std::endl;
                success = false;
                continue;
            }

            // 创建输出文件
            FILE* outFile = fopen(outputFilename.c_str(), "wb");
            if (!outFile) {
                std::cerr << "无法创建输出文件: " << outputFilename << std::endl;
                unzCloseCurrentFile(uf);
                success = false;
                continue;
            }

            // 读取并写入文件数据
            char buffer[8192];
            int bytesRead;
            while ((bytesRead = unzReadCurrentFile(uf, buffer, sizeof(buffer))) > 0) {
                fwrite(buffer, 1, bytesRead, outFile);
            }

            fclose(outFile);
            unzCloseCurrentFile(uf);

            // 移动到下一个文件
            if (i < gi.number_entry - 1) {
                if (unzGoToNextFile(uf) != UNZ_OK) {
                    std::cerr << "无法移动到下一个文件" << std::endl;
                    success = false;
                    break;
                }
            }
        }
        unzClose(uf);
        if (success) {
            std::cout << "解压完成" << std::endl;
        }
        return success;
    }
};

void printUsage() {
    std::cout << "用法:" << std::endl;
    std::cout << "  创建zip: tool -c <输出zip文件> <文件或目录1> [文件或目录2] ..." << std::endl;
    std::cout << "  解压zip: tool -d <输入zip文件> [输出目录]" << std::endl;
    std::cout << "示例:" << std::endl;
    std::cout << "  tool -c archive.zip file1.txt documents/ images/" << std::endl;
    std::cout << "  tool -d archive.zip ./output/" << std::endl;
}

int main(int argc, char* argv[]) {
    if (argc < 3) {
        printUsage();
        return 1;
    }

    std::string mode = argv[1];
    if (mode == "-c" || mode == "--compress") {
        if (argc < 4) {
            std::cerr << "错误: 创建zip需要至少一个输入文件或目录" << std::endl;
            printUsage();
            return 1;
        }

        std::string zipFilename = argv[2];
        std::vector<std::string> pathsToAdd;
        
        for (int i = 3; i < argc; i++) {
            pathsToAdd.push_back(argv[i]);
        }
        if (!ZipUtility::createZip(zipFilename, pathsToAdd)) {
            return 1;
        }
    }
    else if (mode == "-d" || mode == "--decompress") {
        std::string zipFilename = argv[2];
        std::string outputDir = "";
        if (argc >= 4) {
            outputDir = argv[3];
            // 确保输出目录以路径分隔符结尾
            if (outputDir.back() != '/' && outputDir.back() != '\\') {
                outputDir += "/";
            }
        }
        if (!ZipUtility::extractZip(zipFilename, outputDir)) {
            return 1;
        }
    }
    else {
        std::cerr << "错误: 未知模式 '" << mode << "'" << std::endl;
        printUsage();
        return 1;
    }
    return 0;
}
编译后我们得到

在这里插入图片描述

我们如果要使用这个程序,我们可以使用命令提示符,找到文件所在目录
在这里插入图片描述
我们新建一个文件aaa.txt
在这里插入图片描述

使用命令

zlib_zip.exe -c archive.zip aaa.txt

在这里插入图片描述
我们可以得到
在这里插入图片描述
解压缩

zlib_zip.exe -d archive.zip output/

在这里插入图片描述

在这里插入图片描述
当然这只是一个极其简单的一个解压缩程序,实际上我们还需要考虑大文件处理,多线程压缩等问题

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐