解决Minizip压缩后解压时的头部错误问题

最近,在处理文件压缩的任务时,我遇到了一个有趣的问题。使用Minizip库进行文件压缩后,在解压过程中收到了一个关于"头部错误"的警告。尽管这个警告看似令人担忧,但解压操作最终仍然能够成功完成文件的解压。这引发了我的好奇心,我决定深入探究这个问题。

首先,想分享一下我使用的压缩代码:

bool XXXCompressor::compressData(const std::string &input_file_name, const std::string &output_file_name)
{
    // 打开ZIP文件,如果不存在则创建
    zipFile zf = zipOpen(output_file_name.c_str(), APPEND_STATUS_CREATE);
    if (zf == NULL)
    {
        LOGE("Error opening ZIP file. output_file_name: %s", output_file_name.c_str());
        return false;
    }

    // 打开要压缩的文件
    FILE *file_to_zip = fopen(input_file_name.c_str(), "rb");
    if (!file_to_zip)
    {
        LOGE("Error opening file to zip.  input_file_name: %s", input_file_name.c_str());
        zipClose(zf, NULL);
        return false;
    }

    // 定义ZIP条目
    zip_fileinfo zfi;
    memset(&zfi, 0, sizeof(zfi));

    size_t found = input_file_name.find_last_of("/\\");
    std::string filename_zip;
    if (found != std::string::npos)
    {
        filename_zip = input_file_name.substr(found + 1);
        filename_zip = filename_zip + ".log";
    }

    // 打开ZIP中的新文件条目
    if (zipOpenNewFileInZip(zf, filename_zip.c_str(), &zfi,
                            NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION) != ZIP_OK)
    {
        LOGE("Error opening file in ZIP.");
        fclose(file_to_zip);
        zipClose(zf, NULL);
        return false;
    }

    // 读取文件内容并写入ZIP
    // char buffer[1024];
    memset(buffer, 0, sizeof(buffer));
    unsigned int len;
    while ((len = fread(buffer, 1, sizeof(buffer), file_to_zip)) > 0)
    {
        if (zipWriteInFileInZip(zf, buffer, len) < 0)
        {
            LOGE("Error writing file in ZIP.");
            break;
        }
    }

    // 关闭ZIP中的文件条目
    if (zipCloseFileInZip(zf) != ZIP_OK)
    {
        LOGE("Error closing file in ZIP.");
    }

    // 关闭文件和ZIP文件
    fclose(file_to_zip);
    if (zipClose(zf, NULL) != 0)
    {
        LOGE("Error closing ZIP file.");
    }

    return true; // 压缩成功
}

这段代码在压缩文件时表现良好,但在解压时却出现了一些不和谐的声音。如下图:

经过一系列的测试和研究,我发现这个“头部错误”的警告可能是由于Minizip在解压时对文件头部的某些预期与实际不符所导致的。 这种情况虽然并未影响到文件的最终解压结果,但它确实引起了我对压缩过程可靠性的疑虑。

为了解决这个问题,我查阅了Minizip的官方文档和社区讨论,寻找是否有其他用户遇到类似问题的解决方案。发现缺失了filetime操作,即:

#ifdef _WIN32
# include <direct.h>
# include <io.h>
#else
# include <unistd.h>
# include <utime.h>
# include <sys/types.h>
# include <sys/stat.h>
#endif

#ifdef _WIN32
        #define USEWIN32IOAPI
        #include "iowin32.h"
#endif
#ifdef _WIN32
/* f: name of file to get info on, tmzip: return value: access,
   modification and creation times, dt: dostime */
static int filetime(const char *f, tm_zip *tmzip, uLong *dt) {
  (void)tmzip;
  int ret = 0;
  {
      FILETIME ftLocal;
      HANDLE hFind;
      WIN32_FIND_DATAA ff32;

      hFind = FindFirstFileA(f,&ff32);
      if (hFind != INVALID_HANDLE_VALUE)
      {
        FileTimeToLocalFileTime(&(ff32.ftLastWriteTime),&ftLocal);
        FileTimeToDosDateTime(&ftLocal,((LPWORD)dt)+1,((LPWORD)dt)+0);
        FindClose(hFind);
        ret = 1;
      }
  }
  return ret;
}
#elif defined(__unix__) || defined(__unix) || defined(__APPLE__)
/* f: name of file to get info on, tmzip: return value: access,
   modification and creation times, dt: dostime */
static int filetime(const char *f, tm_zip *tmzip, uLong *dt) {
  (void)dt;
  int ret=0;
  struct stat s;        /* results of stat() */
  struct tm* filedate;
  time_t tm_t=0;

  if (strcmp(f,"-")!=0)
  {
    char name[MAXFILENAME+1];
    size_t len = strlen(f);
    if (len > MAXFILENAME)
      len = MAXFILENAME;

    strncpy(name, f,MAXFILENAME-1);
    /* strncpy doesn't append the trailing NULL, of the string is too long. */
    name[ MAXFILENAME ] = '\0';

    if (name[len - 1] == '/')
      name[len - 1] = '\0';
    /* not all systems allow stat'ing a file with / appended */
    if (stat(name,&s)==0)
    {
      tm_t = s.st_mtime;
      ret = 1;
    }
  }
  filedate = localtime(&tm_t);

  tmzip->tm_sec  = filedate->tm_sec;
  tmzip->tm_min  = filedate->tm_min;
  tmzip->tm_hour = filedate->tm_hour;
  tmzip->tm_mday = filedate->tm_mday;
  tmzip->tm_mon  = filedate->tm_mon ;
  tmzip->tm_year = filedate->tm_year;

  return ret;
}
#else
/* f: name of file to get info on, tmzip: return value: access,
   modification and creation times, dt: dostime */
static int filetime(const char *f, tm_zip *tmzip, uLong *dt) {
    (void)f;
    (void)tmzip;
    (void)dt;
    return 0;
}
#endif

之后将下面这行语句加入压缩前的代码中即可

filetime(filename_zip.c_str(),&zfi.tmz_date,&zfi.dosDate);

在接下来的段落中,我将详细分享我的解决方案和一些额外的心得体会,希望能帮助到遇到类似问题的朋友们。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值