Ruby парсинг gzip двоичной строки - PullRequest
4 голосов
/ 10 января 2012

У меня есть двоичная строка, содержащая два сцепленных gzip binarys. (Я читаю двоичный файл журнала, который объединяет два файла gzip вместе)

Другими словами, у меня есть эквивалент:

require 'zlib'
require 'stringio'

File.open('t1.gz', 'w') do |f|
  gz = Zlib::GzipWriter.new(f)
  gz.write 'part one'
  gz.close
end

File.open('t2.gz', 'w') do |f|
  gz = Zlib::GzipWriter.new(f)
  gz.write 'part 2'
  gz.close
end


contents1 = File.open('t1.gz', "rb") {|io| io.read }
contents2 = File.open('t2.gz', "rb") {|io| io.read }

c = contents1 + contents2

gz = Zlib::GzipReader.new(StringIO.new(c))

gz.each do | l |
    puts l
end

Когда я пытаюсь распаковать объединенную строку, я получаю только первую строку. Как мне получить обе строки?

Ответы [ 4 ]

3 голосов
/ 10 января 2012
while c
  io = StringIO.new(c)
  gz = Zlib::GzipReader.new(io)
  gz.each do | l |
    puts l
  end
  c = gz.unused   # take unprocessed portion of the string as the next archive
end

См. ruby-doc .

1 голос
/ 10 января 2012

Формат gzip использует нижний колонтитул, который содержит контрольные суммы для ранее сжатых данных.Как только нижний колонтитул достигнут, больше не может быть больше данных для того же потока данных gziped.

Кажется, что читатель Ruby Gzip только что завершил чтение после первого обнаруженного нижнего колонтитула, что технически правильно, хотя многиереализации вызывают ошибку, если есть еще данные.Я не знаю точно о поведении Ruby здесь.

Дело в том, что вы не можете просто объединить необработанные байтовые потоки и ожидать, что все будет работать.Вы должны адаптировать потоки и переписать верхние и нижние колонтитулы.См. этот вопрос для деталей.

Или вы можете распаковать потоки, объединить их и повторно сжать, но это, очевидно, создает некоторые накладные расходы ...

0 голосов
/ 03 апреля 2014

Это правильный способ обеспечить чтение всего файла.Даже если неиспользованный может быть ноль, это не означает, что конец исходного файла gzipped достигнут.

File.open(path_to_file) do |file|
  loop do
    gz = Zlib::GzipReader.new file
    puts gz.read

    unused = gz.unused
    gz.finish

    adjust = unused.nil? ? 0 : unused.length
    file.pos -= adjust
    break if file.pos == file.size
  end
end
0 голосов
/ 11 сентября 2013

Принятый ответ не сработал для меня.Вот моя модифицированная версия.Обратите внимание на различное использование gz.unused.

. Кроме того, вы должны вызывать finish в экземпляре GzipReader, чтобы избежать утечек памяти.*

Наше распакованное содержимое соответствует оригиналам:

> shasum /usr/share/dict/web*
a62edf8685920f7d5a95113020631cdebd18a185  /usr/share/dict/web2
b0870457df2b8cae06a88657a198d9b52f8e2b0a  /usr/share/dict/web2a
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...