Как я могу читать построчно, используя интерфейс Boost IOStreams для файлов Gzip? - PullRequest
16 голосов
/ 21 июня 2011

Мне удалось интегрировать API-интерфейсы поддержки Iostream для чтения сжатых файлов. Я следовал за документацией на странице наддува и получил следующий код:

std::stringstream outStr;  
ifstream file("file.gz", ios_base::in | ios_base::binary);  
try {  
    boost::iostreams::filtering_istreambuf in;  
    in.push(boost::iostreams::gzip_decompressor());  
    in.push(file);  
    boost::iostreams::copy(in, outStr);  
}  
catch(const boost::iostreams::gzip_error& exception) {  
    int error = exception.error();  
    if (error == boost::iostreams::gzip::zlib_error) {  
       //check for all error code    
    }   
}  

Код работает нормально (поэтому, пожалуйста, игнорируйте любые опечатки и ошибки, приведенные выше :)).

  1. Похоже, что приведенный выше код прочтет полный файл и сохранит его в памяти при создании filtering_istreambuf. Это правда, из моего расследования это выглядит так для меня? Если файл читается в память, этот код может быть проблемой для больших файлов (с чем я имею дело).
  2. Мой текущий код читает gzip с помощью API gzgets из zlib строка за строкой. Есть ли способ сделать построчное чтение, используя API-интерфейсы повышения?

1 Ответ

22 голосов
/ 21 июня 2011

1) Да, приведенный выше код copy() поместит весь файл в буфер строк outStr. Согласно описанию копии

Копия шаблона функции считывает данные из заданной модели Source и записывает их в заданную модель Sink, пока не будет достигнут конец потока.

2) переключиться с filtering_istreambuf на filtering_istream и std :: getline () будет работать:

#include <iostream>
#include <fstream>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/gzip.hpp>
int main()
{
    std::ifstream file("file.gz", std::ios_base::in | std::ios_base::binary);
    try {
        boost::iostreams::filtering_istream in;
        in.push(boost::iostreams::gzip_decompressor());
        in.push(file);
        for(std::string str; std::getline(in, str); )
        {
            std::cout << "Processed line " << str << '\n';
        }
    }
    catch(const boost::iostreams::gzip_error& e) {
         std::cout << e.what() << '\n';
    }
}

(вы можете std::cout << file.tellg() << '\n'; в этом цикле, если вам нужны доказательства. Он увеличится в значительных кусках, но не будет равен длине файла с самого начала)

...