boost gzip_decompressor не работает, где gunzip успешен

Один из наших продуктов в работе включает файлы со следующей структурой:

A STRING WITH SOME CONTENT IDENTIFYING THE FILES CONTENTS
A STRING ON ROW 2
A STRING ON ROW 3
A STRING ON ROW 4
<binary data starts here and is gzipped>

Теперь, если я сделаю это, я могу распаковать содержимое и воссоздать несжатую версию того же файла:

INPUT=FILEA.COMPRESSED
OUTPUT=FILEB.UNCOMPRESSED
head -n5 $INPUT > $OUTPUT
cat $INPUT | tail --lines=+5 | gunzip >> $OUTPUT

# At this point I'm left with a file structure as follows:
A STRING WITH SOME CONTENT IDENTIFYING THE FILES CONTENTS
A STRING ON ROW 2
A STRING ON ROW 3
A STRING ON ROW 4
<uncompressed content>

Я пытаюсь совершить этот же подвиг с помощью буста. Повышение всегда бросает gzip_error код 4 который gzip.hpp раскрывается как bad_header.

Несомненно, файлы, над которыми я работаю, не являются пуленепробиваемыми и создаются очень старой устаревшей системой.

Мой главный вопрос: Если gunzip может это сделать … есть ли твик или флаг, который я пропускаю с помощью boost, который может сделать это тоже?

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

#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <sstream>
#include <iostream>
#include <fstream>

// Open File
ifstream file("myfile", ios::in|ios::binary);

int line = 1;
char c;
while (!file.eof() && line < 5){
// I do do 'way' more error checking and proper handling here
// in real code, but you get the point.. I'm moving the cursor
// past the last new line and the beginning of what is otherwise
// compressed content.
file.get(c);
if(c == '\n')line++;
}

stringstream ss;
// Store rest of binary data into stringstream
while(!file.eof()){
file.get(c);
ss.put(c);
}
// Close File
file.close();

// Return file pointer to potential gzip stream
ss.seekg(0, ios::beg);
try
{
stringstream gzipped(ss.str());
io::filtering_istream gunzip;
gunzip.push(io::gzip_decompressor());
gunzip.push(gzipped);
copy(gunzip, ss);
}
catch(io::gzip_error const&  ex)
// always throws error code 4 here (bad_header)
cout << "Exception: " << ex.error() << endl;

Вот еще одна полезная информация, которая может помочь:

  • ОПЕРАЦИОННЫЕ СИСТЕМЫ: Redhat 5,7
  • Увеличение: boost-1.33.1-10 (хранилище el5)
  • Платформа: x86_64
  • GCC: версия 4.1.2 20080704 (Red Hat 4.1.2-46)

Мой Makefile также имеет следующие строки в компоновщике:

LDFLAGS = -lz -lboost_iostreams

0

Решение

Я не уверен, является ли это основной причиной вашей ошибки, но ваше использование file.eof() это неверно. Функция возвращает true только после того, как вы попытались прочитать после конца файла. Он НЕ сообщает вам, если ваше следующее чтение не удастся.

while(!file.eof()){ //1
file.get(c);  // 2
ss.put(c);    // 3
}

В этом цикле, если вы читаете последний действительный символ в строке 2, затем выводите его в 3. Затем он снова проверяет условие в строке 1. Поскольку вы еще не пытались прочитать конец файла, file.eof() возвращает ложь, поэтому условие цикла истинно. Затем он пытается прочитать следующий символ, который терпит неудачу, оставляя c без изменений. Строка 3 затем помещает этот недопустимый символ в ss,

Это приводит к дополнительному символу в конце потока. Я не уверен, что это единственная проблема, но, вероятно, это одна из них.

Редактировать:

Хорошо, посмотрев на это, я не уверен на 100% ПОЧЕМУ это происходит, но это потому, что вы повторно используете струнный поток ss, Либо позвони ss.seekp(0, ios::begin) перед выполнением копирования или используйте отдельный поток строк.

Лично вместо копирования ss в gzippedЯ бы написал прямо в gzipped из входного файла, а затем вывести через копию в сс.

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]