【问题标题】:How to compress a C++ string using Zstd?如何使用 Zstd 压缩 C++ 字符串?
【发布时间】:2020-01-04 19:02:10
【问题描述】:

我对 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 arguments\n");
        printf("usage:\n");
        printf("%s FILE\n", exeName);
        return 1;
    }

    const char* const inFilename = argv[1];

    char* const outFilename = createOutFilename_orDie(inFilename);
    compress_orDie(inFilename, outFilename);
    free(outFilename);
    return 0;
}

我的问题是,是否有人可以指导我查看示例代码/sn-p,展示如何使用 Zstd 压缩 C++ 字符串?

【问题讨论】:

    标签: c++ string compression zstd


    【解决方案1】:

    使用string::c_str(),您可以获得指向数组的指针,该数组包含以空字符结尾的字符序列(C 字符串),表示字符串对象的当前值。

    【讨论】:

      【解决方案2】:

      在我看来,Boost library (version 1.70.0) 的最新版本通过Zstd 将支持压缩添加到其iostreams 子模块。我可以管理以下C++ 代码 sn-p 但似乎旧版本的Boost 不支持Zstd 压缩(我在Debian 10 上使用Boost 1.67.0 没有Zstd支持。)

      我现在可以组装的代码是这样的(它基于来自here的代码):

          #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();
          }
      

      【讨论】:

        【解决方案3】:
        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
        

        【讨论】:

        • 您好,欢迎来到 SO!虽然此代码可能会回答问题,但提供有关它如何和/或为什么解决问题的额外上下文将提高​​答案的长期价值。请阅读tourHow do I write a good answer?
        • 感谢您的建议,我稍后会修改我的答案
        【解决方案4】:

        这是 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
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-11-12
          • 2021-10-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-02-05
          • 1970-01-01
          相关资源
          最近更新 更多