Распаковка 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
:
- Использование встроенного 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;
}
- Родной
inflate
API: Coliru Link. Подробнее об этом в руководстве по ссылке выше и здесь. Мой код почти полностью дублирует предоставленную ссылку и довольно длинный, поэтому я не буду репостировать.