使用libarchive创建带目录结构的Zip文件异常问题求助
解决libarchive打包目录生成异常Zip文件的问题
问题根源
你的代码存在三个核心问题:
- 错误遍历源目录条目:遍历源目录的直接子条目并为每个条目单独创建
archive_read_disk读取器,导致整个目录结构被打包成"嵌套"Zip文件(外层Zip仅含一个与源目录同名的文件,实际内容才是真正的目录归档)。 - 压缩算法配置错误:使用
archive_write_set_compression_compress是通用压缩配置,Zip格式应使用专门的deflate压缩算法。 - 手动文件读取冗余且易出错:用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
相关产品推荐
相关产品推荐

