【问题标题】:C++ zlib compression of strings in fileC ++ zlib压缩文件中的字符串
【发布时间】:2013-02-26 14:25:35
【问题描述】:

我一直在尝试压缩字符串并将它们保存到文本文件中,然后读取数据并解压缩。然而,当我尝试解压缩读取的字符串时,我得到一个 Z_BUF_ERROR (-5) 并且该字符串可能会或可能不会解压缩。

在控制台,我可以整天压缩/解压:

std::string s = zlib_compress("HELLO asdfasdf asdf asdfasd f asd f asd f awefo@8 892y*(@Y");
std::string e = zlib_decompress(s);

字符串e 将毫无困难地返回原始字符串。

但是,当我这样做时:

zlib_decompress(readFile(filename));

我收到了Z_BUF_ERROR。我认为这可能部分是由于文件中的隐藏字符,但我不太确定。

这是我的readFile 函数:

std::string readFile(std::string filename)
{
    std::ifstream file;
    file.open(filename.c_str(), std::ios::binary);

    file.seekg (0, std::ios::end);
    int length = file.tellg();
    file.seekg (0, std::ios::beg);

    char * buffer = new char[length];

    file.read(buffer, length);
    file.close();

    std::string data(buffer);

    return data;
}

当我写压缩数据时,我使用:

void writeFile(std::string filename, std::string data)
{
    std::ofstream file;
    file.open(filename.c_str(), std::ios::binary);
    file << data;
    file.close();
}

如果需要,我会展示我用来解压/压缩的函数,但如果它在没有文件 IO 的情况下工作,我觉得问题是一个 IO 问题。

【问题讨论】:

  • 您正在阅读的文件有多长?塞维拉MB?还是就像您使用的字符串一样?
  • 虽然我没有立即明白为什么您的代码不能按预期工作,但我相信我看到了内存泄漏:readFile() 中的 buffer 永远不会被释放。
  • @ahans 哇。谢谢。我没注意到。
  • 最好完全摆脱手动分配的缓冲区。您可以使用vector&lt;char&gt; buf,然后将&amp;buf[0] 传递给file.read。或者查看这个问题的公认答案:stackoverflow.com/questions/1816319/…
  • zlib_compresszlib_decompress 函数在做什么,你能提供一些源代码吗?它们不是来自原始 zlib。

标签: c++ string file compression zlib


【解决方案1】:

首先,您正在处理可能嵌入或不嵌入空字符的二进制数据。 std::string 并不是真正的正确容器,但如果操作正确,您可以处理嵌入的空字符。但是,使用std::string 来存储某些文件记录了某种期望,而您违反了该约定。

其次,std::string data(buffer); 行并没有按照您的想法执行 - 这是您应该用来从以空字符结尾的 C 字符串构造字符串的构造函数。您在这里处理二进制数据,因此您可能没有将完整的缓冲区放入字符串中,因为它在缓冲区中间遇到空终止符,或者它在缓冲区的末尾运行直到它找到一个空值(或一个段错误)。如果您绝对肯定必须使用 std::string,请使用“正确”构造函数,即 std::string data(buffer, length);

话虽如此,您使用了错误的数据结构 - 您想要的是 char/unsigned char 的动态数组。那将是std::vector,而不是std::string。顺便说一句,您还应该通过 const 引用将参数传递给 readFilewriteFile,您编写的代码将复制字符串,如果您传递给 writeFile() 的缓冲区很大,这将导致对内存消耗和性能的不利影响,而且完全没有必要。

【讨论】:

    【解决方案2】:

    由于文件可能包含'\0' 字符,您应该在将内容分配给std::string 时指定大小。

    std::string data(buffer, length);
    

    【讨论】:

      【解决方案3】:

      对于它的价值,这里是你可以改变readFile()writeFile()的方法:

      std::vector<char> readFile(const std::string& filename)
      {
          std::ifstream file;
          file.open(filename.c_str(), std::ios::binary);
      
          file.seekg (0, std::ios::end);
          const int length = file.tellg();
          file.seekg (0, std::ios::beg);
      
          std::vector<char> data(length);
          file.read(&data[0], length);
          file.close();
      
          return data;
      }
      
      void writeFile(const std::string& filename, const std::vector<char>& data)
      {
          std::ofstream file;
          file.open(filename.c_str(), std::ios::binary);
          file.write(&data[0], data.size());
          file.close();
      }
      

      然后您还可以更改您的 compress()decompress() 函数以使用 std::vector&lt;char&gt;。另请注意,到目前为止,代码缺少任何错误处理。例如,如果文件不存在会发生什么?调用file.open() 后,您可以通过if (!file) { /* error handling */ } 来检查是否有任何错误。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-01-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多