使用增强和过滤流解压缩档案

时间:2018-01-22 20:11:44

标签: c++ c++11 boost

我正在解压缩大文件,包含指定的压缩数据块的各种方式。 我写了以下代码:

// input_file - path to file
std::ifstream file(input_file, std::ios_base::in | std::ios_base::binary);
//move to begin of n-th data block, compressed by zlib
file.seekg(offset, std::ios_base::beg);
boost::iostreams::filtering_streambuf<boost::iostreams::input> in;
in.push(boost::iostreams::zlib_decompressor());
in.push(file);
// write decompressed data to output file
boost::iostreams::copy(in, output);

我的理解是这一行

boost::iostreams::copy(in, output); 

将开始解压缩并复制数据,直到文件结束,在这种情况下这是不需要的。

重要的是,我知道压缩数据的正确偏移量和长度。

Boost文档说:

Source的模型可以定义如下:

struct Source {
    typedef char        char_type;
    typedef source_tag  category;
    std::streamsize read(char* s, std::streamsize n) 
    {
        // Read up to n characters from the input 
        // sequence into the buffer s, returning   
        // the number of characters read, or -1 
        // to indicate end-of-sequence.
    }
};

我想继承ifstream类,覆盖它的read方法,并在该方法内部计算读取的字节数,如果该块中没有更多数据则返回-1,但遗憾的是,它似乎无效。

我写道:

class ifstream_t : public std::ifstream{
     public:
     ifstream_t(const std::string& fp, std::ios_base::openmode mode = std::ios_base::in) : std::ifstream(fp, mode){}
     std::streamsize read(char* s, std::streamsize n) {
         // calculate remaining bytes 
         return -1;
     }   
};

并将其用于:

ifstream_t file(this->fp, std::ios_base::in | std::ios_base::binary);
boost::iostreams::filtering_streambuf<boost::iostreams::input> in;
in.push(boost::iostreams::zlib_decompressor());
in.push(file);
boost::iostreams::copy(in, output);

方法读取,来自我的类​​,未调用。

1 个答案:

答案 0 :(得分:0)

  

我的理解是这一行

 boost::iostreams::copy(in, output);
     

将开始解压缩并复制数据,直到文件结束,在这种情况下这是不需要的。

我刚试过这个,事实并非如此。解压缩器在压缩数据完成时正确检测流的结束。

我创建了一个包含自己压缩源的随机数据的文件:¹

(dd if=/dev/urandom bs=1 count=$((0x3214a)); cat main.cpp | zlib-flate -compress; dd if=/dev/urandom bs=1 count=$((0x3214a))) > input.txt 

使用带有硬编码偏移的程序和该文件时:

<强> Live On Coliru

#include <boost/iostreams/filter/zlib.hpp>
#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/copy.hpp>
#include <fstream>
#include <iostream>

int main() {
    static std::string const input_file = "input.txt";
    static size_t      const offset     = 0x3214a;
    std::ostream& output = std::cout;

    // input_file - path to file
    std::ifstream file(input_file, std::ios_base::in | std::ios_base::binary);

    //move to begin of n-th data block, compressed by zlib
    file.seekg(offset, std::ios_base::beg);
    boost::iostreams::filtering_streambuf<boost::iostreams::input> in;

    in.push(boost::iostreams::zlib_decompressor());
    in.push(file);

    // write decompressed data to output file
    boost::iostreams::copy(in, output);
}

很高兴再现自己的来源,你可以看到coliru上的直播

coliru上没有 - zib-flate,所以我使用了python:

python -c 'import zlib; import sys; sys.stdout.write(zlib.compress(sys.stdin.read()))'