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

Posted

技术标签:

【中文标题】使用增强和过滤流解压缩档案【英文标题】:Decompressing archives with boost and filtering streams 【发布时间】:2018-01-22 20:11:43 【问题描述】:

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

// 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】:

我的理解是这一行

 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()))'

【讨论】:

以上是关于使用增强和过滤流解压缩档案的主要内容,如果未能解决你的问题,请参考以下文章

在 S3 中使用 lambda 函数解压缩档案真的很慢

linux压缩解压缩命令

tar压缩解压缩命令详解

Linux 压缩解压缩命令详解

如何从 Unix 命令行递归解压缩目录及其子目录中的档案?

tar 解压缩命令