zstd c++ string 壓縮&解壓

zstd 簡介

維基百科定義:c++

Zstandard(或Zstd)是由Facebook的Yann Collet開發的一個無損數據壓縮算法。該名稱也指其C語言的參考實現。第1版的實現於2016年8月31日發佈爲自由軟件
設計Zstandard的目的是提供一個相似於DEFLATE算法的壓縮比,但更快,特別是解壓縮快的算法。git

  1. 它的壓縮級別從負5級(最快)到22級(壓縮速度最慢,可是壓縮比最高)能夠調節。
  2. zstd包裏面有壓縮和解壓縮的並行(多線程)實現。從1.3.2版本(2017年10月)開始,zstd 有選擇地實現很是長的搜索和重複數據消除(--long,128MiB窗口),相似於rzip或lrzip。
  3. 壓縮速度在最快和最慢級別之間能夠相差20倍或更多,而解壓縮速度通通很快,在最快和最慢級別之間相差不到20%。
  4. Zstandard命令行有一個「自適應」(--adapt)模式,根據I/O條件改變壓縮級別,主要是寫入輸出的速度。
  5. Zstd在其最大壓縮級別下的壓縮比接近lzma、lzham和ppmx,而且比lza或bzip2性能更好。
  6. Zstandard達到了當前的Pareto邊界,由於它解壓縮的速度比任何其餘當前可用的算法都要快,而且有相似的或者更好的壓縮比。
  7. 字典對小文件的壓縮比有很大的影響,因此Zstandard能夠使用用戶提供的壓縮字典。它還提供了一種訓練模式,可以從一組樣本生成一個字典。
  8. 特別是,能夠加載一個字典來處理文件之間具備冗餘的大型文件集,但不必定在每一個文件(例如日誌文件)內。

c++中應用

最多見的就是對於字符串的壓縮,下邊給出字符串源碼github

歡迎訪問個人github https://github.com/hashyong/zstd_util算法

//
// -*- coding: utf-8-unix; -*-
//  Copyright (c) 2020 Tencent, Inc.
//     All rights reserved.
//
// Date:   2020/11/30 13:45
// File:   zstd.cc
// Desc:
//

#include "util.h"

#include "third_party/zstd/zstd.h"

namespace util {

int Util::CompressString(const string& src, string& dst, int compressionlevel) {
  size_t const cBuffSize = ZSTD_compressBound(src.size());
  dst.resize(cBuffSize);
  auto dstp = const_cast<void*>(static_cast<const void*>(dst.c_str()));
  auto srcp = static_cast<const void*>(src.c_str());
  size_t const cSize = ZSTD_compress(dstp, cBuffSize, srcp, src.size(), compressionlevel);
  auto code = ZSTD_isError(cSize);
  if (code) {
    return code;
  }
  dst.resize(cSize);
  return code;
}

int Util::DecompressString(const string& src, string& dst) {
  size_t const cBuffSize = ZSTD_getFrameContentSize(src.c_str(), src.size());

  if (0 == cBuffSize) {
    return cBuffSize;
  }

  if (ZSTD_CONTENTSIZE_UNKNOWN == cBuffSize) {
    return StreamDecompressString(src, dst);
  }

  if (ZSTD_CONTENTSIZE_ERROR == cBuffSize) {
    return -2;
  }

  dst.resize(cBuffSize);
  auto dstp = const_cast<void*>(static_cast<const void*>(dst.c_str()));
  auto srcp = static_cast<const void*>(src.c_str());
  size_t const cSize = ZSTD_decompress(dstp, cBuffSize, srcp, src.size());
  auto code = ZSTD_isError(cSize);
  if (code) {
    return code;
  }
  dst.resize(cSize);
  return code;
}

int Util::StreamCompressString(const string& src, string& dst, int compressionlevel) {
  size_t const buffInSize = ZSTD_CStreamInSize();
  string buffInTmp;
  buffInTmp.reserve(buffInSize);
  auto buffIn = const_cast<void*>(static_cast<const void*>(buffInTmp.c_str()));

  auto buffOutSize = ZSTD_CStreamOutSize();
  string buffOutTmp;
  buffOutTmp.reserve(buffOutSize);
  auto buffOut = const_cast<void*>(static_cast<const void*>(buffOutTmp.c_str()));

  ZSTD_CCtx* const cctx = ZSTD_createCCtx();
  ZSTD_CCtx_setParameter(cctx, ZSTD_c_compressionLevel, compressionlevel);

  size_t const toRead = buffInSize;
  auto local_pos = 0;
  auto buff_tmp = const_cast<char*>(buffInTmp.c_str());
  for (;;) {
    size_t read = src.copy(buff_tmp, toRead, local_pos);
    local_pos += read;

    int const lastChunk = (read < toRead);
    ZSTD_EndDirective const mode = lastChunk ? ZSTD_e_end : ZSTD_e_continue;

    ZSTD_inBuffer input = {buffIn, read, 0};
    int finished;

    do {
      ZSTD_outBuffer output = {buffOut, buffOutSize, 0};
      size_t const remaining = ZSTD_compressStream2(cctx, &output, &input, mode);
      dst.insert(dst.end(), buffOutTmp.begin(), buffOutTmp.begin() + output.pos);
      finished = lastChunk ? (remaining == 0) : (input.pos == input.size);
    } while (!finished);

    if (lastChunk) {
      break;
    }
  }

  return 0;
}

int Util::StreamDecompressString(const string& src, string& dst, int compressionlevel) {
  size_t const buffInSize = ZSTD_DStreamInSize();
  string buffInTmp;
  buffInTmp.reserve(buffInSize);
  auto buffIn = const_cast<void*>(static_cast<const void*>(buffInTmp.c_str()));

  auto buffOutSize = ZSTD_DStreamOutSize();
  string buffOutTmp;
  buffOutTmp.reserve(buffOutSize);
  auto buffOut = const_cast<void*>(static_cast<const void*>(buffOutTmp.c_str()));

  ZSTD_DCtx* const dctx = ZSTD_createDCtx();

  size_t const toRead = buffInSize;
  size_t read;
  size_t last_ret = 0;
  size_t local_pos = 0;
  auto buff_tmp = const_cast<char*>(buffInTmp.c_str());

  while ((read = src.copy(buff_tmp, toRead, local_pos))) {
    local_pos += read;
    ZSTD_inBuffer input = {buffIn, read, 0};
    while (input.pos < input.size) {
      ZSTD_outBuffer output = {buffOut, buffOutSize, 0};
      size_t const ret = ZSTD_decompressStream(dctx, &output, &input);
      dst.insert(dst.end(), buffOutTmp.begin(), buffOutTmp.begin() + output.pos);
      last_ret = ret;
    }
  }

  if(last_ret != 0) {
    return -3;
  }

  return 0;
}

}  // namespace util
相關文章
相關標籤/搜索