QZipWriter повреждает архивы при работе с большими файлами

Мне необходимо архивировать (со сжатием или без - не принципиально) файлы разной величины, для этого я (в рамках работы на Qt) использовал незадокументированный QZipWriter, который, как мне казалось, хорошо работал, пока я тестировал его на маленьких данных (до 3гб), но стоило мне попробовать сжать папку на 16гб (каждый файл я сжимаю по отдельности, так как не нашёл в qzip возможности сжимать разом папки), как возникают CRC-ошибки контрольных сумм при попытке открыть архив (при этом сам QZipWriter видимых ошибок не выдаёт).

Вот, как я архивирую отдельный файл:

QFile file(filepath);
if (!file.open(QIODevice::ReadOnly))
    return false;

QString correctDirName = relativePath;
if (!correctDirName.isEmpty() && correctDirName.back() != QDir::separator()) {
    correctDirName.push_back(QDir::separator());
}

_zip->addFile(correctDirName + QFileInfo(filepath).fileName(), file.readAll());
file.close();

_progressedBytes += QFileInfo(filepath).size();
updateProgressBar();
return true;

Вот, как я архивирую папку (надо сказать, что папка заведомо имеет определённую сигнатуру, так что я при архивации, как вы можете видеть, ориентируюсь именно на неё):

QDir dir = QDir(path);
if (!dir.cdUp()) {
    emit message(ReportingMessage::BAD_PROJECT_WAY);
    return false;
}

QString projectDirName = dir.dirName();

QFileInfoList dirContent = dir.entryInfoList();
for each (const auto& var in dirContent) //Сжатие всех файлов в папке проекта
{
    if (_stoped) {
        _reportingResult = ReportingResult::CANCELED;
        return false;
    }

    if (!var.isDir())
        compressFile(var.absoluteFilePath(), projectDirName);
}

if (dirContent.front().isDir()) //Сжатие всех файлов в папке Temp (если она есть)
{
    QFileInfo tmpFolder = dirContent.back();
    if (tmpFolder.fileName() != TmpDirName) {
        emit message(ReportingMessage::UNEXPECTED_PROJECT_SGINATURE);
        return false;
    }

    dirContent = QDir(tmpFolder.absoluteFilePath()).entryInfoList();
    for each (const auto & var in dirContent)
    {
        if (_stoped) {
            _reportingResult = ReportingResult::CANCELED;
            return false;
        }

        if (!var.isDir())
            compressFile(var.absoluteFilePath(), projectDirName + QDir::separator() + TmpDirName);
    }
}

return true;

У меня есть подозрение, что метод архивации файла можно как-либо модифицировать, чтобы он был более отказоустойчивым.


Ответы (1 шт):

Автор решения: BOPOHOB

Решается переходом на любую библиотеку, например miniz:

#include <miniz/miniz.h>
#include <miniz/miniz_zip.h>

// обжимает data размером size, результат выгружает в result, возвращает размер result
size_t zip(void** result, const char* data, const size_t size)
{
  struct zip_t* zip = zip_stream_open(nullptr, 0, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
  {
    zip_entry_open(zip, "frac_project");
    {
      zip_entry_write(zip, data, size);
    }
    zip_entry_close(zip);
  }
  const int resultSize(zip_stream_copy(zip, result, nullptr));

  zip_stream_close(zip);

  return resultSize;
}

// принимает массив байт, возвращает его же в сжатом виде
QByteArray& compress(const QByteArray &data)
{
  QByteArray out;
  void* result;
  const int resultSize(zip(&result, data.data(), data.size()));
  out.setRawData(static_cast<char*>(result), resultSize);
  return out;
}
→ Ссылка