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 документ. Кто-либо знает, как я могу правильно сделать это?

7
задан the Tin Man 18 November 2015 в 19:28
поделиться

1 ответ

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

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

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.

23
ответ дан 6 December 2019 в 07:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: