zstd c++ string 壓縮&解壓
- 2020 年 12 月 14 日
- 筆記
zstd 簡介
維基百科定義:
Zstandard(或Zstd)是由Facebook的Yann Collet開發的一個無損數據壓縮演算法。該名稱也指其C語言的參考實現。第1版的實現於2016年8月31日發布為自由軟體
設計Zstandard的目的是提供一個類似於DEFLATE演算法的壓縮比,但更快,特別是解壓縮快的演算法。
- 它的壓縮級別從負5級(最快)到22級(壓縮速度最慢,但是壓縮比最高)可以調節。
- zstd包裡面有壓縮和解壓縮的並行(多執行緒)實現。從1.3.2版本(2017年10月)開始,zstd 有選擇地實現非常長的搜索和重複數據消除(–long,128MiB窗口),類似於rzip或lrzip。
- 壓縮速度在最快和最慢級別之間可以相差20倍或更多,而解壓縮速度統統很快,在最快和最慢級別之間相差不到20%。
- Zstandard命令行有一個「自適應」(–adapt)模式,根據I/O條件改變壓縮級別,主要是寫入輸出的速度。
- Zstd在其最大壓縮級別下的壓縮比接近lzma、lzham和ppmx,並且比lza或bzip2性能更好。
- Zstandard達到了當前的Pareto邊界,因為它解壓縮的速度比任何其他當前可用的演算法都要快,並且有類似的或者更好的壓縮比。
- 字典對小文件的壓縮比有很大的影響,所以Zstandard可以使用用戶提供的壓縮字典。它還提供了一種訓練模式,能夠從一組樣本生成一個字典。
- 特別是,可以載入一個字典來處理文件之間具有冗餘的大型文件集,但不一定在每個文件(例如日誌文件)內。
c++中應用
最常見的就是對於字元串的壓縮,下邊給出字元串源碼
歡迎訪問我的github //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