我对C++很陌生,我想通过压缩库压缩Zstd
std:string
对象,但到目前为止,我无法通过谷歌搜索找到用于此目的的C++示例代码。我找到了示例 C 代码,但似乎他们使用的是 C 样式字符数组而不是std:string
对象。
示例 C 代码: https://github.com/facebook/zstd/blob/dev/examples/simple_compression.c
/*
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
* in the COPYING file in the root directory of this source tree).
* You may select, at your option, one of the above-listed licenses.
*/
#include <stdio.h> // printf
#include <stdlib.h> // free
#include <string.h> // strlen, strcat, memset
#include <zstd.h> // presumes zstd library is installed
#include "common.h" // Helper functions, CHECK(), and CHECK_ZSTD()
static void compress_orDie(const char* fname, const char* oname)
{
size_t fSize;
void* const fBuff = mallocAndLoadFile_orDie(fname, &fSize);
size_t const cBuffSize = ZSTD_compressBound(fSize);
void* const cBuff = malloc_orDie(cBuffSize);
/* Compress.
* If you are doing many compressions, you may want to reuse the context.
* See the multiple_simple_compression.c example.
*/
size_t const cSize = ZSTD_compress(cBuff, cBuffSize, fBuff, fSize, 1);
CHECK_ZSTD(cSize);
saveFile_orDie(oname, cBuff, cSize);
/* success */
printf("%25s : %6u -> %7u - %s n", fname, (unsigned)fSize, (unsigned)cSize, oname);
free(fBuff);
free(cBuff);
}
static char* createOutFilename_orDie(const char* filename)
{
size_t const inL = strlen(filename);
size_t const outL = inL + 5;
void* const outSpace = malloc_orDie(outL);
memset(outSpace, 0, outL);
strcat(outSpace, filename);
strcat(outSpace, ".zst");
return (char*)outSpace;
}
int main(int argc, const char** argv)
{
const char* const exeName = argv[0];
if (argc!=2) {
printf("wrong argumentsn");
printf("usage:n");
printf("%s FILEn", exeName);
return 1;
}
const char* const inFilename = argv[1];
char* const outFilename = createOutFilename_orDie(inFilename);
compress_orDie(inFilename, outFilename);
free(outFilename);
return 0;
}
我的问题是是否有人可以将我引导到一个示例代码/片段,显示如何使用 Zstd 压缩C++字符串?
在我看来,最新版本的Boost library (version 1.70.0)
已通过Zstd
将支持压缩添加到其iostreams
子模块中。我可以管理以下C++
代码片段,但似乎旧版本的Boost
不支持Zstd
压缩(我在没有Zstd
支持的Debian 10
上使用Boost 1.67.0
。
我目前可以设法组装的代码是这样的(它基于这里的代码(:
#include <iostream>
#include <algorithm>
#include <string>
#include <sstream>
#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/filter/zstd.hpp>
std::string compress(std::string& data)
{
namespace bio = boost::iostreams;
std::stringstream compressed;
std::stringstream origin(data);
bio::filtering_streambuf<bio::input> out;
out.push(bio::zstd_compressor(bio::zstd_params(bio::zstd::default_compression)));
out.push(origin);
bio::copy(out, compressed);
return compressed.str();
}
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;
}
}
ZSTD_freeCCtx(cctx);
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;
}
}
ZSTD_freeDCtx(dctx);
if(last_ret != 0) {
return -3;
}
return 0;
}
} // namespace util
使用string::c_str()
可以获取指向数组的指针,该数组包含以 null 结尾的字符序列(C 字符串(,表示字符串对象的当前值。
> Habedi的回答很简洁,做得很好。
为了完整起见,下面您将在 Debian 书虫上找到使用 boost 1.74.0-14 的解压缩功能。
//g++ test.cc -lboost_iostreams -o test
#include <iostream>
#include <string>
#include <sstream>
#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/filter/zstd.hpp>
std::string compress(std::string& data)
{
namespace bio = boost::iostreams;
std::stringstream compressed;
std::stringstream origin(data);
bio::filtering_streambuf<bio::input> out;
out.push(bio::zstd_compressor(bio::zstd_params(bio::zstd::default_compression)));
out.push(origin);
bio::copy(out, compressed);
return compressed.str();
}
std::string decompress(std::string& data)
{
namespace bio = boost::iostreams;
std::stringstream decompressed;
std::stringstream origin(data);
bio::filtering_streambuf<bio::input> out;
out.push(bio::zstd_decompressor(bio::zstd_params(bio::zstd::default_compression)));
out.push(origin);
bio::copy(out, decompressed);
return decompressed.str();
}
int main(int argc, char *argv[])
{
std::string original = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
std::string compressed_encoded = compress(original);
std::cout << compressed_encoded << std::endl;
std::string decompressed_decoded = decompress(compressed_encoded);
std::cout << decompressed_decoded << std::endl;
if (original == decompressed_decoded) {
std::cout << "Successfully compressed/decompressedn";
}
return 0;
}
这是 STL 函子样式包装器:
#ifndef ZSTD_UTILITY_H
#define ZSTD_UTILITY_H
#include <type_traits>
#include <string>
namespace zstd {
#include <zstd.h>
} // namespace zstd
static constexpr int kMinCLevel = 1;
static constexpr int kMaxCLevel = 22;
static constexpr int kDefaultCLevel = kMinCLevel;
template<typename ChType>
struct ZstdCompression final {
using char_type = typename std::char_traits<ChType>::char_type;
using ContainerType = std::basic_string<char_type>;
inline auto operator()(const char_type* input, const size_t inputSize, const int level = kDefaultCLevel) {
assert(0 < inputSize);
assert(kMinCLevel <= level);
assert(kMaxCLevel >= level);
const size_t required = zstd::ZSTD_compressBound(inputSize);
ContainerType block(required, 0x0);
const size_t actual = zstd::ZSTD_compress(block.data(), block.size(), input, inputSize, level);
assert(!zstd::ZSTD_isError(actual));
block.erase(block.begin() + actual, block.end());
return block;
}
template<typename Container, typename IteratorValueType = typename std::iterator_traits<typename Container::iterator>::value_type>
inline auto operator()(const Container& input, const int level = kDefaultCLevel) -> std::enable_if_t<std::is_same_v<char_type, IteratorValueType>, ContainerType> {
return this->operator()(input.data(), input.size(), level);
}
};
using ZstdCompressor = ZstdCompression<char>;
template<typename ChType>
struct ZstdDeCompression final {
using char_type = typename std::char_traits<ChType>::char_type;
using ContainerType = std::basic_string<char_type>;
inline auto operator()(const char_type* input, const size_t inputSize) {
assert(0 < inputSize);
const size_t size = zstd::ZSTD_getFrameContentSize(input, inputSize);
assert(ZSTD_CONTENTSIZE_ERROR != size);
assert(ZSTD_CONTENTSIZE_UNKNOWN != size);
ContainerType block(size, 0x0);
const size_t actual = zstd::ZSTD_decompress(block.data(), block.size(), input, inputSize);
assert(!zstd::ZSTD_isError(actual));
assert(actual == size);
return block;
}
template<typename Container, typename IteratorValueType = typename std::iterator_traits<typename Container::iterator>::value_type>
inline auto operator()(const Container& input) -> std::enable_if_t<std::is_same_v<char_type, IteratorValueType>, ContainerType> {
return this->operator()(input.data(), input.size());
}
};
using ZstdDeCompressor = ZstdDeCompression<char>;
#endif // ZSTD_UTILITY_H