Распаковка gzip-файла в память с использованием libarchive

Я пытаюсь программно распаковать файл gzip в память и имитировать команду gzip -d file.gz используя проект архива. Файл фактически взят из ответа http со следующим заголовком Accept-Encoding: gzip, deflate

Здесь моя попытка прочитать файл. Я не ожидаю, что он не будет работать, так как файл gzipped не имеет записей (он сжат как поток) и archive_read_next_header пытается прочитать следующий файл из архива.

Есть ли альтернатива этой функции, которая извлекает все данные из сжатого файла.

archive_read_support_format_raw(archive); 
archive_read_support_filter_all(archive);
archive_read_support_compression_all(archive)

archive_read_open_memory(archive, file_data, file_size);
struct archive_entry *entry;
la_ssize_t total, size;
char *buf;    
int status = archive_read_next_header(archive, &entry);

Возможно, кто-то может опубликовать минимальный пример кода, который решает эту проблему? Кроме того, есть ли возможность узнать, есть ли в архиве gzip записи или нет?

1 ответ

Одной из возможных альтернатив является использование boost::iostreams Библиотека, которая поставляется со встроенным GZIP-фильтром и позволяет делать то, что вы хотите - потоковую распаковку из GZIP-файла в памяти. Вот ссылка на фильтр gzip и фрагмент из того же:

ifstream file("hello.gz", ios_base::in | ios_base::binary);
filtering_streambuf<input> in;
in.push(gzip_decompressor());
in.push(file);
boost::iostreams::copy(in, cout);

Изменить: На самом деле гораздо лучший фрагмент доступен здесь /questions/47274382/raspakujte-dannyie-v-pamyati-s-pomoschyu-boost-gzipdecompressor/47274396#47274396

Есть два способа сделать это, используя zlib:

  1. Использование встроенного GzFile API: Coliru Link - подробнее об этом здесь
int inf(FILE* fp) {
    auto gzf = ::gzdopen(fileno(fp), "r");
    assert(::gztell(gzf) == 0);
    std::cout << "pos: " << ::gztell(gzf) << std::endl;
    ::gzseek(gzf, 18L, SEEK_SET);
    char buf[768] = {0};
    ::gzread(gzf, buf, sizeof(buf)); // use a custom size as needed
    std::cout << buf << std::endl; // Print file contents from 18th char onward
    ::gzclose(gzf);
    return 0;
}
  1. Родной inflate API: Coliru Link. Подробнее об этом в руководстве по ссылке выше и здесь. Мой код почти полностью дублирует предоставленную ссылку и довольно длинный, поэтому я не буду репостировать.
Другие вопросы по тегам