Может ли boost iostreams читать и сжимать gzip-файлы на лету?

Я читаю gzip-файл, используя boost iostreams: отлично работает следующее:

 namespace io = boost::iostreams;
  io::filtering_istream in;
  in.push(boost::iostreams::basic_gzip_decompressor<>());
  in.push(io::file_source("test.gz"));
  stringstream ss;
  copy(in, ss);

Тем не менее, я не хочу, чтобы в память читался весь сжатый gzip-файл. Я хочу иметь возможность читать файл постепенно.

Например, если у меня есть структура данных X, которая инициализирует себя из istream,

X x;
x.read(in);

терпит неудачу. Предположительно, это связано с тем, что нам, возможно, придется возвращать символы в поток, если мы делаем частичные потоки. Есть идеи, поддерживает ли boost iostreams это?


person ATemp    schedule 28.02.2012    source источник
comment
Будет ли работать для вас выполнение такой операции, как вызов getline(), а затем compressing() через цикл?   -  person user99545    schedule 29.02.2012
comment
@ user99545: Нет: потому что X создает себя из двоичных данных.   -  person ATemp    schedule 29.02.2012
comment
Я не понимаю, почему бы и нет. Я использовал boost iostreams для чтения и записи потоков, сжатых zlib таким образом.   -  person Ferruccio    schedule 29.02.2012


Ответы (2)


Согласно документации iostream тип boost::io::filtering_istream является производным от std::istream. То есть должна быть возможность передать это везде, где ожидается std::istream&. Если у вас есть ошибки во время выполнения, потому что вам нужно unget() или putback() символов, вам следует взглянуть на параметр pback_size, который указывает, сколько символов возвращается максимум. Я не видел в документации, какое значение по умолчанию для этого параметра.

Если это не решит вашу проблему, можете ли вы описать, в чем именно заключается ваша проблема? Судя по всему должно работать.

person Dietmar Kühl    schedule 28.02.2012

Я думаю, вам нужно написать свой собственный фильтр. Например, чтобы прочитать .tar.gz и вывести содержащиеся в нем файлы, я написал что-то вроде

//using namespace std;
namespace io = boost::iostreams;

struct tar_expander
{
    tar_expander() : out(0), status(header)
    {
    }
    ~tar_expander()
    {
        delete out;
    }

    /* qualify filter */
    typedef char char_type;
    struct category :
        io::input_filter_tag,
        io::multichar_tag
    { };

    template<typename Source>
    void fetch_n(Source& src, std::streamsize n = block_size)
    {
           /* my utility */
           ....
    }

    // Read up to n filtered characters into the buffer s,
    // returning the number of characters read or -1 for EOF.
    // Use src to access the unfiltered character sequence
    template<typename Source>
    std::streamsize read(Source& src, char* s, std::streamsize n)
    {
      fetch_n(src);
      const tar_header &h = cast_buf<tar_header>();
      int r;

      if (status == header)
      {
          ...
      }
      std::ofstream *out;
      size_t fsize, stored;

      static const size_t block_size = 512;
      std::vector<char> buf;

      enum { header, store_file, archive_end } status;
   }
}

Моя функция read(Source &...) при вызове получает разархивированный текст. Чтобы использовать фильтр:

ifstream file("/home/..../resample-1.8.1.tar.gz", ios_base::in | ios_base::binary);
io::filtering_streambuf<io::input> in;
in.push(tar_expander());
in.push(io::gzip_decompressor());
in.push(file);
io::copy(in, cout);
person CapelliC    schedule 28.02.2012