Descompacte (zip, tar, tag.gz) arquivos com ruby
Pergunta
Eu quero descompactar um monte de arquivos zip. Existe um módulo ou script que verifica qual o formato do arquivo zip é e descompacta-lo? Isso deve funcionar no Linux, eu não me importo com outros SOs.
Solução
Para extrair arquivos de um arquivo .tar.gz você pode usar os seguintes métodos de pacotes distribuídos com Ruby:
require 'rubygems/package'
require 'zlib'
tar_extract = Gem::Package::TarReader.new(Zlib::GzipReader.open('Path/To/myfile.tar.gz'))
tar_extract.rewind # The extract has to be rewinded after every iteration
tar_extract.each do |entry|
puts entry.full_name
puts entry.directory?
puts entry.file?
# puts entry.read
end
tar_extract.close
Cada entrada do tipo Gem :: pacote :: TarReader :: entrada aponta para um arquivo ou pasta dentro do arquivo .tar.gz.
código semelhante pode ser utilizado (substitua Reader com Writer) para gravar arquivos para um arquivo .tar.gz.
Outras dicas
A maneira mais fácil é provavelmente usar Zlib
Zlib é uma biblioteca Ruby. O que se segue é um programa simples para pegar um arquivo zipado de um URL particular, descompactá-lo e colar o seu conteúdo para a tela.
require 'zlib'
require 'open-uri'
uri = "www.somedomain.com/filename.gz"
source = open(uri)
gz = Zlib::GzipReader.new(source)
result = gz.read
puts result
Espero que isso ajude.
Apesar de resposta de Florian é certo, ele não leva em conta tar LongLinks (Tente extrair jdk-7u40-linux i586.tar.gz da oracle: P). O código a seguir deve ser capaz de fazer isso:
require 'rubygems/package'
require 'zlib'
TAR_LONGLINK = '././@LongLink'
tar_gz_archive = '/path/to/archive.tar.gz'
destination = '/where/extract/to'
Gem::Package::TarReader.new( Zlib::GzipReader.open tar_gz_archive ) do |tar|
dest = nil
tar.each do |entry|
if entry.full_name == TAR_LONGLINK
dest = File.join destination, entry.read.strip
next
end
dest ||= File.join destination, entry.full_name
if entry.directory?
File.delete dest if File.file? dest
FileUtils.mkdir_p dest, :mode => entry.header.mode, :verbose => false
elsif entry.file?
FileUtils.rm_rf dest if File.directory? dest
File.open dest, "wb" do |f|
f.print entry.read
end
FileUtils.chmod entry.header.mode, dest, :verbose => false
elsif entry.header.typeflag == '2' #Symlink!
File.symlink entry.header.linkname, dest
end
dest = nil
end
end
Draco, thx para você trecho . Alguns TARs codificar diretórios como caminhos terminando com '/' - veja este Wiki. Examlple alcatrão é servidor Oracle JRE 7u80 para Windows . Isto irá trabalhar para eles:
require 'fileutils'
require 'rubygems/package'
require 'zlib'
TAR_LONGLINK = '././@LongLink'
Gem::Package::TarReader.new( Zlib::GzipReader.open tar_gz_archive ) do |tar|
dest = nil
tar.each do |entry|
if entry.full_name == TAR_LONGLINK
dest = File.join destination, entry.read.strip
next
end
dest ||= File.join destination, entry.full_name
if entry.directory? || (entry.header.typeflag == '' && entry.full_name.end_with?('/'))
File.delete dest if File.file? dest
FileUtils.mkdir_p dest, :mode => entry.header.mode, :verbose => false
elsif entry.file? || (entry.header.typeflag == '' && !entry.full_name.end_with?('/'))
FileUtils.rm_rf dest if File.directory? dest
File.open dest, "wb" do |f|
f.print entry.read
end
FileUtils.chmod entry.header.mode, dest, :verbose => false
elsif entry.header.typeflag == '2' #Symlink!
File.symlink entry.header.linkname, dest
else
puts "Unkown tar entry: #{entry.full_name} type: #{entry.header.typeflag}."
end
dest = nil
end
end
end