#include "XNCodeZip.h" #include #include #include #include #include namespace fs = std::filesystem; int XNCodeZip::Zip(const std::string &srcPath, const std::string &dstPath, std::string &errorMsg) { // 检查源路径是否存在 if (!fs::exists(srcPath)) { errorMsg = "源路径不存在: " + srcPath; return -1; } // 确保目标目录存在 fs::path dstDir = fs::path(dstPath).parent_path(); if (!fs::exists(dstDir)) { fs::create_directories(dstDir); } // 打开zip文件 int err = 0; zip_t *zip = zip_open(dstPath.c_str(), ZIP_CREATE | ZIP_TRUNCATE, &err); if (zip == nullptr) { char errstr[1024]; zip_error_to_str(errstr, sizeof(errstr), err, errno); errorMsg = "无法创建zip文件: " + std::string(errstr); return -1; } // 递归添加文件和目录 std::function addToZip = [&](const fs::path ¤tPath, const fs::path &relativePath) { if (fs::is_directory(currentPath)) { // 添加目录 std::string dirName = relativePath.string() + "/"; zip_dir_add(zip, dirName.c_str(), ZIP_FL_OVERWRITE); // 递归处理子目录和文件 for (const auto &entry : fs::directory_iterator(currentPath)) { fs::path newRelativePath = relativePath / entry.path().filename(); addToZip(entry.path(), newRelativePath); } } else if (fs::is_regular_file(currentPath)) { // 添加文件 std::string fileName = relativePath.string(); zip_source_t *source = zip_source_file(zip, currentPath.c_str(), 0, 0); if (source == nullptr) { errorMsg = "无法创建zip源: " + fileName; return; } if (zip_file_add(zip, fileName.c_str(), source, ZIP_FL_OVERWRITE) < 0) { zip_source_free(source); errorMsg = "无法添加文件到zip: " + fileName; return; } } }; // 开始压缩 fs::path srcDir(srcPath); fs::path baseName = srcDir.filename(); addToZip(srcDir, baseName); // 关闭zip文件 zip_close(zip); return 0; } int XNCodeZip::Unzip(const std::string &srcPath, const std::string &dstPath, std::string &errorMsg) { // 检查源路径是否存在 if (!fs::exists(srcPath)) { errorMsg = "源路径不存在: " + srcPath; return -1; } // 确保目标目录存在 fs::path dstDir = fs::path(dstPath); if (!fs::exists(dstDir)) { fs::create_directories(dstDir); } // 打开zip文件 int err = 0; zip_t *zip = zip_open(srcPath.c_str(), 0, &err); if (zip == nullptr) { char errstr[1024]; zip_error_to_str(errstr, sizeof(errstr), err, errno); errorMsg = "无法打开zip文件: " + std::string(errstr); return -1; } // 获取zip文件中的条目数量 zip_int64_t numEntries = zip_get_num_entries(zip, 0); if (numEntries < 0) { errorMsg = "无法获取zip文件条目数量"; zip_close(zip); return -1; } // 检测根目录名称(去除额外层级) std::string rootDirName; bool hasRootDir = false; // 检查第一个条目来确定根目录结构 if (numEntries > 0) { struct zip_stat st; if (zip_stat_index(zip, 0, 0, &st) >= 0) { std::string firstEntry = st.name; size_t slashPos = firstEntry.find('/'); if (slashPos != std::string::npos) { rootDirName = firstEntry.substr(0, slashPos); hasRootDir = true; } } } // 遍历并解压所有条目 for (zip_int64_t i = 0; i < numEntries; ++i) { // 获取条目信息 struct zip_stat st; if (zip_stat_index(zip, i, 0, &st) < 0) { errorMsg = "无法获取zip条目信息"; zip_close(zip); return -1; } // 跳过空条目 if (st.size == 0 && st.name[strlen(st.name) - 1] == '/') { continue; } // 构建目标文件路径,去除根目录层级 std::string relativePath = st.name; if (hasRootDir && relativePath.find(rootDirName + "/") == 0) { relativePath = relativePath.substr(rootDirName.length() + 1); } // 如果去除根目录后路径为空,跳过 if (relativePath.empty()) { continue; } fs::path targetPath = dstDir / relativePath; // 如果是目录,创建目录 if (relativePath[relativePath.length() - 1] == '/') { fs::create_directories(targetPath); continue; } // 确保文件的父目录存在 fs::create_directories(targetPath.parent_path()); // 检查文件是否已存在 if (fs::exists(targetPath)) { // 可以选择跳过、覆盖或询问用户 // 这里选择覆盖已有文件 fs::remove(targetPath); } // 打开zip条目 zip_file_t *zipFile = zip_fopen_index(zip, i, 0); if (zipFile == nullptr) { errorMsg = "无法打开zip条目: " + std::string(st.name); zip_close(zip); return -1; } // 创建目标文件 std::ofstream outFile(targetPath, std::ios::binary); if (!outFile.is_open()) { errorMsg = "无法创建目标文件: " + targetPath.string(); zip_fclose(zipFile); zip_close(zip); return -1; } // 读取并写入文件内容 char buffer[8192]; zip_int64_t bytesRead; while ((bytesRead = zip_fread(zipFile, buffer, sizeof(buffer))) > 0) { outFile.write(buffer, bytesRead); if (!outFile.good()) { errorMsg = "写入文件失败: " + targetPath.string(); outFile.close(); zip_fclose(zipFile); zip_close(zip); return -1; } } // 检查读取是否成功 if (bytesRead < 0) { errorMsg = "读取zip条目失败: " + std::string(st.name); outFile.close(); zip_fclose(zipFile); zip_close(zip); return -1; } // 关闭文件 outFile.close(); zip_fclose(zipFile); } // 关闭zip文件 zip_close(zip); return 0; }