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