You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用libarchive创建带目录结构的Zip文件异常问题求助

解决libarchive打包目录生成异常Zip文件的问题

问题根源

你的代码存在三个核心问题:

  1. 错误遍历源目录条目:遍历源目录的直接子条目并为每个条目单独创建archive_read_disk读取器,导致整个目录结构被打包成"嵌套"Zip文件(外层Zip仅含一个与源目录同名的文件,实际内容才是真正的目录归档)。
  2. 压缩算法配置错误:使用archive_write_set_compression_compress是通用压缩配置,Zip格式应使用专门的deflate压缩算法。
  3. 手动文件读取冗余且易出错:用QFile手动读取文件内容写入归档,不仅代码冗余,还可能因未处理libarchive返回值导致数据写入不完整。

修正后的代码

bool KArchiveManager::pack(const QString& srcDirPath)
{
    struct archive* a = nullptr;
    struct archive* disk = nullptr;
    struct archive_entry* entry = nullptr;
    int r;

    // 初始化写归档
    a = archive_write_new();
    archive_write_set_format_zip(a);
    // 改用Zip标准的deflate压缩算法
    archive_write_set_compression_deflate(a);
    QString outPath = srcDirPath + ".zip";
    
    r = archive_write_open_filename_w(a, outPath.toStdWString().c_str());
    if (r != ARCHIVE_OK)
    {
        QString msg = QString("打开归档文件失败: %1").arg(archive_error_string(a));
        emit packArchiveError(msg);
        goto cleanup;
    }

    QDir compressDir(srcDirPath);
    if (!compressDir.exists())
    {
        emit packArchiveError(tr("待压缩目录不存在"));
        goto cleanup;
    }

    // 直接打开整个源目录作为磁盘读取源,无需遍历子条目
    disk = archive_read_disk_new();
    archive_read_disk_set_standard_lookup(disk);
    r = archive_read_disk_open(disk, srcDirPath.toStdString().c_str());
    if (r != ARCHIVE_OK)
    {
        QString msg = QString("读取磁盘目录失败: %1").arg(archive_error_string(disk));
        emit packArchiveError(msg);
        goto cleanup;
    }

    // 遍历目录下所有条目(自动递归子目录)
    while (true)
    {
        r = archive_read_next_header(disk, &entry);
        if (r == ARCHIVE_EOF)
            break;
        if (r != ARCHIVE_OK)
        {
            QString msg = QString("读取条目头失败: %1").arg(archive_error_string(disk));
            emit packArchiveError(msg);
            goto cleanup;
        }

        // 调整条目路径:去掉源目录绝对路径前缀,保留相对结构
        QString sourcePath = archive_entry_pathname(entry);
        QString relativePath = sourcePath.mid(srcDirPath.size() + 1);
        archive_entry_set_pathname(entry, relativePath.toLocal8Bit().constData());

        // 写入条目头
        r = archive_write_header(a, entry);
        if (r != ARCHIVE_OK)
        {
            QString msg = QString("写入条目头失败: %1").arg(archive_error_string(a));
            emit packArchiveError(msg);
            goto cleanup;
        }

        // 非目录文件,用libarchive自动拷贝数据,替代手动文件操作
        if (archive_entry_filetype(entry) != AE_IFDIR)
        {
            r = archive_read_data_into_fd(disk, archive_write_get_fd(a));
            if (r != ARCHIVE_OK)
            {
                QString msg = QString("拷贝文件数据失败: %1").arg(archive_error_string(disk));
                emit packArchiveError(msg);
                goto cleanup;
            }
        }

        archive_entry_free(entry);
        archive_read_disk_descend(disk);
    }

    // 正常关闭归档
    archive_write_close(a);
    archive_read_close(disk);
cleanup:
    // 确保资源释放,避免内存泄漏
    if (a) archive_write_free(a);
    if (disk) archive_read_free(disk);
    return r == ARCHIVE_OK || r == ARCHIVE_EOF;
}

关键修改说明

  • 直接读取整个源目录:不再手动遍历子条目,让libarchive自动递归处理所有子目录和文件,保证目录结构正确。
  • 修正压缩算法:替换为Zip标准的deflate压缩,避免通用压缩导致的格式兼容问题。
  • 自动拷贝文件数据:使用archive_read_data_into_fd让libarchive完成数据拷贝,简化代码同时避免手动文件操作的潜在错误。
  • 统一资源清理:通过goto cleanup确保任何错误场景下都能正确释放libarchive资源。

内容的提问来源于stack exchange,提问作者key zhao

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 14:57:51