Zlib в Ruby, чтобы распаковать.gz

У меня есть файл.gz, который содержит документ XML. Кто-нибудь знает, как правильно использовать Zlib? Пока у меня есть следующий код:

require 'zlib'
Zlib::GzipReader.open('PRIDE_Exp_Complete_Ac_1015.xml.gz') { |gz|
    g = File.new("PRIDE_Exp_Complete_Ac_1015.xml", "w")
      g.write(gz)
      g.close()
}

Но это создает пустой XML-документ. Кто-нибудь знает, как я могу правильно это сделать?

2 ответа

Решение

Zlib::GzipReader работает как большинство IOподобные классы делают в Ruby. У вас есть open вызов, и когда вы передаете ему блок, блок получит IOобъект Подумайте об этом, это удобный способ сделать что-то с файлом или ресурсом на время блока.

Но это означает, что в вашем примере gz является IO-подобный объект, а не собственно содержимое файла gzip, как вы ожидаете. Вам все еще нужно read от этого, чтобы добраться до этого. Самое простое исправление будет тогда:

g.write(gz.read)

Обратите внимание, что это прочитает все содержимое несжатого gzip в память.

Если все, что вы действительно делаете, это копирование из одного файла в другой, вы можете использовать более эффективный IO.copy_stream метод. Ваш пример может выглядеть так:

Zlib::GzipReader.open('PRIDE_Exp_Complete_Ac_1015.xml.gz') do | input_stream |
  File.open("PRIDE_Exp_Complete_Ac_1015.xml", "w") do |output_stream|
    IO.copy_stream(input_stream, output_stream)
  end
end

За кулисами, это будет пытаться использовать sendfile Системный вызов доступен в некоторых конкретных ситуациях в Linux. В противном случае он будет выполнять копирование в быстрых блоках кода C размером 16 КБ за раз. Это я узнал из исходного кода Ruby 1.9.1.

Вот один строковый Ruby ( cd .git/ first и укажите путь к любому объекту):

ruby -rzlib -e 'print Zlib::Inflate.new.inflate(STDIN.read)' < ./74/c757240ec596063af8cd273ebd9f67073e1208
Другие вопросы по тегам