经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
使用libzip压缩文件和文件夹
来源:cnblogs  作者:charlee44  时间:2024/7/12 23:13:22  对本文有异议

简单说说自己遇到的坑:

  1. 分清楚三个组件:zlib、minizip和libzip。zlib是底层和最基础的C库,用于使用Deflate算法压缩和解压缩文件流或者单个文件,但是如果要压缩文件夹就很麻烦,主要是不知道如何归档,在zip内部形成对应的目录。这时就需要用更高级别的库,也就是minizip或libzip。

  2. minizip、libzip随着版本迭代接口一直变化,我连续使用了通义千问、文心一言、gemini三个AI,基本上没给出能使用的代码,主要是函数接口总是不对,或者参数多了或者少了。像这种情况就不要再参考AI给出的答案了,赶紧翻官方文档才是正经。

  3. minizip和libzip都是基于zlib实现的,都尝试使用过,感觉还是libzip的接口设计更清晰一点,官方文档说明也还不错。

  4. 压缩文件夹的功能需要借助于操作文件系统的库来组织zip内部的归档目录,我这里使用的是C++17的std::filesystem。

具体代码实现如下:

  1. #include <zip.h>
  2. #include <filesystem>
  3. #include <fstream>
  4. #include <iostream>
  5. using namespace std;
  6. void CompressFile2Zip(std::filesystem::path unZipFilePath,
  7. const char* relativeName, zip_t* zipArchive) {
  8. std::ifstream file(unZipFilePath, std::ios::binary);
  9. file.seekg(0, std::ios::end);
  10. size_t bufferSize = file.tellg();
  11. char* bufferData = (char*)malloc(bufferSize);
  12. file.seekg(0, std::ios::beg);
  13. file.read(bufferData, bufferSize);
  14. //第四个参数如果非0,会自动托管申请的资源,直到zip_close之前自动销毁。
  15. zip_source_t* source =
  16. zip_source_buffer(zipArchive, bufferData, bufferSize, 1);
  17. if (source) {
  18. if (zip_file_add(zipArchive, relativeName, source, ZIP_FL_OVERWRITE) < 0) {
  19. std::cerr << "Failed to add file " << unZipFilePath
  20. << " to zip: " << zip_strerror(zipArchive) << std::endl;
  21. zip_source_free(source);
  22. }
  23. } else {
  24. std::cerr << "Failed to create zip source for " << unZipFilePath << ": "
  25. << zip_strerror(zipArchive) << std::endl;
  26. }
  27. }
  28. void CompressFile(std::filesystem::path unZipFilePath,
  29. std::filesystem::path zipFilePath) {
  30. int errorCode = 0;
  31. zip_t* zipArchive = zip_open(zipFilePath.generic_u8string().c_str(),
  32. ZIP_CREATE | ZIP_TRUNCATE, &errorCode);
  33. if (zipArchive) {
  34. CompressFile2Zip(unZipFilePath, unZipFilePath.filename().string().c_str(),
  35. zipArchive);
  36. errorCode = zip_close(zipArchive);
  37. if (errorCode != 0) {
  38. zip_error_t zipError;
  39. zip_error_init_with_code(&zipError, errorCode);
  40. std::cerr << zip_error_strerror(&zipError) << std::endl;
  41. zip_error_fini(&zipError);
  42. }
  43. } else {
  44. zip_error_t zipError;
  45. zip_error_init_with_code(&zipError, errorCode);
  46. std::cerr << "Failed to open output file " << zipFilePath << ": "
  47. << zip_error_strerror(&zipError) << std::endl;
  48. zip_error_fini(&zipError);
  49. }
  50. }
  51. void CompressDirectory2Zip(std::filesystem::path rootDirectoryPath,
  52. std::filesystem::path directoryPath,
  53. zip_t* zipArchive) {
  54. if (rootDirectoryPath != directoryPath) {
  55. if (zip_dir_add(zipArchive,
  56. std::filesystem::relative(directoryPath, rootDirectoryPath)
  57. .generic_u8string()
  58. .c_str(),
  59. ZIP_FL_ENC_UTF_8) < 0) {
  60. std::cerr << "Failed to add directory " << directoryPath
  61. << " to zip: " << zip_strerror(zipArchive) << std::endl;
  62. }
  63. }
  64. for (const auto& entry : std::filesystem::directory_iterator(directoryPath)) {
  65. if (entry.is_regular_file()) {
  66. CompressFile2Zip(
  67. entry.path().generic_u8string(),
  68. std::filesystem::relative(entry.path(), rootDirectoryPath)
  69. .generic_u8string()
  70. .c_str(),
  71. zipArchive);
  72. } else if (entry.is_directory()) {
  73. CompressDirectory2Zip(rootDirectoryPath, entry.path().generic_u8string(),
  74. zipArchive);
  75. }
  76. }
  77. }
  78. void CompressDirectory(std::filesystem::path directoryPath,
  79. std::filesystem::path zipFilePath) {
  80. int errorCode = 0;
  81. zip_t* zipArchive = zip_open(zipFilePath.generic_u8string().c_str(),
  82. ZIP_CREATE | ZIP_TRUNCATE, &errorCode);
  83. if (zipArchive) {
  84. CompressDirectory2Zip(directoryPath, directoryPath, zipArchive);
  85. errorCode = zip_close(zipArchive);
  86. if (errorCode != 0) {
  87. zip_error_t zipError;
  88. zip_error_init_with_code(&zipError, errorCode);
  89. std::cerr << zip_error_strerror(&zipError) << std::endl;
  90. zip_error_fini(&zipError);
  91. }
  92. } else {
  93. zip_error_t zipError;
  94. zip_error_init_with_code(&zipError, errorCode);
  95. std::cerr << "Failed to open output file " << zipFilePath << ": "
  96. << zip_error_strerror(&zipError) << std::endl;
  97. zip_error_fini(&zipError);
  98. }
  99. }
  100. int main() {
  101. //压缩文件
  102. //CompressFile("C:/Data/Builder/Demo/view.tmp", "C:/Data/Builder/Demo/view.zip");
  103. //压缩文件夹
  104. CompressDirectory("C:/Data/Builder/Demo", "C:/Data/Builder/Demo.zip");
  105. return 0;
  106. }

关于使用的libzip,有以下几点值得注意:

  1. libzip压缩的zip内部的文件名默认采用UTF-8编码。
  2. libzip要求使用正斜杠 ('/') 作为目录分隔符。
  3. libzip操作不同的zip线程安全,操作同一个zip线程不安全。
  4. zip_source_buffer这个函数的接口的第四个参数如果非0,会自动托管申请的资源。官方文档提到需要保证传入zip_source_buffer的数据资源需要保证跟zip_source_t一样的声明周期,但是笔者经过测试,正确的行为应该是传入zip_source_buffer的数据资源需要保证调用zip_close之前都有效,否则就有问题。

原文链接:https://www.cnblogs.com/charlee44/p/18299531

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号