如何缩短libzip中zip_close()函数的执行耗时?
libzip v1.8.0 zip_close() 执行耗时过长问题
问题描述
我在应用中使用libzip v1.8.0压缩文件,但zip_close(..)函数的执行耗时过长——例如压缩10个各32MB的文件需要约3分钟。
代码片段
int err = 0; auto const pZipHandler = ::zip_open(zipPath.c_str(), ZIP_CREATE | ZIP_TRUNCATE, &err); if (!pZipHandler) { PLOGE << "Failed to create a new zip file: " << zipPath; PLOGD << fmt::format("Error code: {}, error: {}", err, zip_strerror(pZipHandler)); PLOGD << "Recordings can still be found in " << recordFolderPath; return C2_ERROR_FAILED; } for(const auto &entry : std::filesystem::directory_iterator(recordFolderPath)) { if(entry.is_regular_file()) { const std::string filePath = entry.path().string(); const std::string fileName = entry.path().filename().string(); auto const pZipSource = zip_source_file(pZipHandler, filePath.c_str(), 0, 0); if (!pZipSource) { PLOGE << "Failed to create zip source for file: " << filePath; zip_close(pZipHandler); return C2_ERROR_FAILED; } if (zip_file_add(pZipHandler, fileName.c_str(), pZipSource, ZIP_CM_STORE) < 0) { PLOGE << "Failed to add file to zip: " << filePath; zip_source_free(pZipSource); zip_close(pZipHandler); return C2_ERROR_FAILED; } } } if(const auto retCode = zip_close(pZipHandler); 0 != retCode) { PLOGE << "Failed to close zip file: " << zipPath; PLOGD << fmt::format("Error code: {}, error: {}", retCode, zip_strerror(pZipHandler)); return C2_ERROR_FAILED; }
待压缩文件列表
root@machine:~# ls -lh /tmp/recordings_1637345115/ -rw-rw-rw- 1 root root 32.0M Nov 19 18:05 IQ-2000000KHz-0.bin -rw-rw-rw- 1 root root 32.0M Nov 19 18:05 IQ-2001000KHz-0.bin -rw-rw-rw- 1 root root 32.0M Nov 19 18:05 IQ-2002000KHz-0.bin -rw-rw-rw- 1 root root 32.0M Nov 19 18:05 IQ-2003000KHz-0.bin -rw-rw-rw- 1 root root 32.0M Nov 19 18:05 IQ-2004000KHz-0.bin -rw-rw-rw- 1 root root 32.0M Nov 19 18:05 IQ-2005000KHz-0.bin -rw-rw-rw- 1 root root 32.0M Nov 19 18:05 IQ-2006000KHz-0.bin -rw-rw-rw- 1 root root 32.0M Nov 19 18:05 IQ-2007000KHz-0.bin -rw-rw-rw- 1 root root 32.0M Nov 19 18:05 IQ-2008000KHz-0.bin -rw-rw-rw- 1 root root 32.0M Nov 19 18:05 IQ-2009000KHz-0.bin -rw-rw-rw- 1 root root 32.0M Nov 19 18:05 IQ-2010000KHz-0.bin
补充信息
- 运行环境为嵌入式Linux系统。
- 应用程序与libzip库均已做优化处理。
- 使用
zip命令行工具压缩时表现类似。 - 耗时接近线性,压缩2个32MB文件约需35秒。
- 主存储写入速度约为10MB/s。
解决方案
1. 耗时原因分析
10个32MB文件总大小320MB,按10MB/s写入速度计算理论耗时约32秒,但实际耗时达3分钟,说明问题并非单纯的顺序写入速度限制。
libzip在zip_close()阶段会完成:文件内容写入、中央目录结构生成与写入、存储介质同步。结合嵌入式存储特性,核心原因是存储介质随机写入性能差——ZIP格式需要在文件末尾追加中央目录,而嵌入式存储(如eMMC、NAND Flash)的随机写入远慢于顺序写入;同时默认模式下libzip会缓存文件内容,zip_close()时一次性写入引发大量随机IO。
2. 优化措施
(1) 启用即时写入模式
添加ZIP_FLUSH_ON_ADD标志,让zip_file_add()时直接写入文件内容,避免zip_close()阶段批量写入:
if (zip_file_add(pZipHandler, fileName.c_str(), pZipSource, ZIP_CM_STORE | ZIP_FLUSH_ON_ADD) < 0) { // 错误处理逻辑不变 }
此操作会将每个文件的内容在添加时立即写入ZIP文件,zip_close()仅需处理中央目录,大幅缩短该阶段耗时。
(2) 预分配ZIP文件空间
嵌入式存储预分配可减少碎片化,提升顺序写入效率。在zip_open()后根据待压缩文件总大小预分配空间:
// 计算待压缩文件总大小 uint64_t totalSize = 0; for(const auto &entry : std::filesystem::directory_iterator(recordFolderPath)) { if(entry.is_regular_file()) { totalSize += entry.file_size(); } } // 预分配空间(额外预留64KB用于中央目录) int fd = open(zipPath.c_str(), O_WRONLY); if (fd != -1) { posix_fallocate(fd, 0, totalSize + 1024 * 64); close(fd); }
(3) 调整存储挂载参数
确保存储介质挂载时使用noatime(禁用访问时间记录)、data=writeback(延迟数据写入)等参数,减少不必要的IO操作:
# 示例挂载命令 mount /dev/mmcblk0p1 /mnt/storage -o noatime,data=writeback
(4) 升级libzip版本
v1.8.0为2021年发布的旧版本,后续版本针对嵌入式IO性能有优化,建议升级至最新稳定版(如v1.10.1)。
内容的提问来源于stack exchange,提问作者Caglayan Dokme
相关产品推荐
相关产品推荐

