在c ++中处理大型gzfile

时间:2014-01-29 09:04:42

标签: c++ file gz

char buffer[1001];
for(;!gzeof(m_fHandle);){ 
         gzread(m_fHandle, buffer, 1000);
     The file I'm handling is more than 1GB.

我将整个文件加载到缓冲区吗?或者我应该malloc并分配大小?

或者我应该逐行加载它?该文件有一个" \ n"对EOL进行标记。如果是这样,我该怎么做才能在c ++中处理gzfile?

2 个答案:

答案 0 :(得分:2)

zlib方法是:

您可以反复调用缓冲区大小有限的gzread。如果您可以确定其最大行长度为BUFLEN:请参阅 Live On Coliru

#include <zlib.h>
#include <iostream>
#include <algorithm>

static const unsigned BUFLEN = 1024;

void error(const char* const msg)
{
    std::cerr << msg << "\n";
    exit(255);
}

void process(gzFile in)
{
    char buf[BUFLEN];
    char* offset = buf;

    for (;;) {
        int err, len = sizeof(buf)-(offset-buf);
        if (len == 0) error("Buffer to small for input line lengths");

        len = gzread(in, offset, len);

        if (len == 0) break;    
        if (len <  0) error(gzerror(in, &err));

        char* cur = buf;
        char* end = offset+len;

        for (char* eol; (cur<end) && (eol = std::find(cur, end, '\n')) < end; cur = eol + 1)
        {
            std::cout << std::string(cur, eol) << "\n";
        }

        // any trailing data in [eol, end) now is a partial line
        offset = std::copy(cur, end, buf);
    }

    // BIG CATCH: don't forget about trailing data without eol :)
    std::cout << std::string(buf, offset);

    if (gzclose(in) != Z_OK) error("failed gzclose");
}

int main()
{
    process(gzopen("test.gz", "rb"));
}

如果您无法知道最大线路大小,我建议稍微抽象一下,并从std::basic_streambuf覆盖underflow得出,这样您就可以std::getline使用istream基于此缓冲区。

更新由于您不熟悉C ++,因此实施您自己的streambuf可能 而不是 是一个好主意。我建议使用c ++库(而不是zlib)。

E.g。 Boost Iostream允许您简单地执行此操作:

<强> Live On Coliru

#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/gzip.hpp>    

namespace io = boost::iostreams;

int main()
{   
    io::filtering_istream in;
    in.push(io::gzip_decompressor());
    in.push(io::file_source("my_file.txt"));
    // read from in using std::istream interface

    std::string line;
    while (std::getline(in, line, '\n'))
    {
         process(line); // your code :)
    }
}

答案 1 :(得分:0)

你说这是一个gz文件。这意味着二进制格式,其中'\ n'对EOL无效(没有二进制文件的EOL概念。)

那就是说,实际上你有两种缓冲区大小的选择。将整个文件加载到内存中对于您作为开发人员处理数据肯定会更容易。但是,就任务所消耗的内存而言,这是一种代价高昂的解决方案。

如果内存是一个问题,那么你需要处理数据。可能一次尝试获取最佳数据量,其中很大一部分取决于从CPU到缓存线,内存总线,SATA总线,甚至是CPU的机器的硬件架构。保存文件的驱动器。

如果这只是你正在解决的问题并且你在现代计算机上运行这个问题,那么1GB就可以保留在内存中了。只需新增一个uint8_t []文件的大小并读取整个内容然后解析数据。

否则,您需要将文件的解析与文件的读取集成在一起。