c++ 如何将boost::iostreams::mapped_file_source与gzip格式的输入文件一起使用

plupiseo  于 2023-02-01  发布在  iOS
关注(0)|答案(1)|浏览(137)

我使用boost::iostreams::mapped_file_source将文本文件从一个特定位置读取到另一个特定位置,并操作每一行(使用g++ -Wall -O3 -lboost_iostreams -o test main.cpp编译):

#include <iostream>
#include <string>
#include <boost/iostreams/device/mapped_file.hpp>

int main() {
    boost::iostreams::mapped_file_source f_read;
    f_read.open("in.txt");

    long long int alignment_offset(0);

    // set the start point
    const char* pt_current(f_read.data() + alignment_offset);
    // set the end point
    const char* pt_last(f_read.data() + f_read.size());
    const char* pt_current_line_start(pt_current);

    std::string buffer;

    while (pt_current && (pt_current != pt_last)) {
        if ((pt_current = static_cast<const char*>(memchr(pt_current, '\n', pt_last - pt_current)))) {
            buffer.assign(pt_current_line_start, pt_current - pt_current_line_start + 1);
            // do something with buffer

            pt_current++;
            pt_current_line_start = pt_current;
        }
    }

    return 0;
}

目前,我想让这段代码也处理gzip文件,并将代码修改为:

#include<iostream>
#include<boost/iostreams/device/mapped_file.hpp>
#include<boost/iostreams/filter/gzip.hpp>
#include<boost/iostreams/filtering_streambuf.hpp>
#include<boost/iostreams/filtering_stream.hpp>
#include<boost/iostreams/stream.hpp>

int main() {
    boost::iostreams::stream<boost::iostreams::mapped_file_source> file;
    file.open(boost::iostreams::mapped_file_source("in.txt.gz"));

    boost::iostreams::filtering_streambuf< boost::iostreams::input > in; 
    in.push(boost::iostreams::gzip_decompressor());
    in.push(file);

    std::istream std_str(&in);
    std::string buffer;
    while(1) {
        std::getline(std_str, buffer);
        if (std_str.eof()) break;
        // do something with buffer
    }   
}

这段代码也很好用,但是我不知道如何像第一段代码那样设置起点(pt_current)和终点(pt_last)。你能告诉我如何在第二段代码中设置这两个值吗?

qrjkbowd

qrjkbowd1#

答案是否定的,这是不可能的。压缩流需要有索引。
真实的的问题是为什么?。您正在使用内存Map文件。执行动态压缩/解压缩只会降低性能并增加内存消耗。
如果您不缺少实际的文件存储,那么您可能应该考虑二进制表示,或者保持文本原样。
二进制表示可以避开使用随机访问的文本文件时所涉及的大部分复杂性。
一些鼓舞人心的示例:

  • 读取Map到内存的CSV文件的最简单方法?
  • 将boost::iostreams::Map文件源与std::multimap配合使用
  • 使用boost迭代mmaped gzip文件

您基本上会发现,文本文件不是随机访问的,压缩使得索引本质上是模糊的(从压缩流偏移到未压缩流偏移没有精确的Map)。
查看zlib发行版中的zran.c示例,如zlib FAQ中所述:
28.* 我可以随机访问压缩流中的数据吗?*
不,不需要做一些准备。如果在压缩时定期使用Z_FULL_FLUSH,小心地在这些点写入所有挂起的数据,并保留这些位置的索引,那么您可以在这些点开始解压缩。您必须小心不要太频繁地使用Z_FULL_FLUSH,因为它会显著降低压缩性能。或者,您可以扫描一次deflate流以生成索引。然后使用该索引进行随机访问。请参见examples/zran.c
¹您可以专门查看并行实现,例如pbzip 2或pigz;它们必须使用这些“块”或“帧”来跨核心调度负载

相关问题