2009-05-13 12 views

risposta

27

Per estrarre i file da un file .tar.gz è possibile utilizzare i seguenti metodi di pacchetti distribuiti con 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 

Ogni voce di tipo Gem::Package::TarReader::Entry punti ad un file o directory all'interno del .tar.gz file.

È possibile utilizzare un codice simile (sostituire Reader with Writer) per scrivere file in un file .tar.gz.

27

Il modo più semplice è quello di utilizzare probabilmente Zlib

Zlib è una libreria Ruby. Quello che segue è un semplice programma per catturare un file con zip da un particolare URL, decomprimerlo e incollarne il contenuto sullo schermo.

require 'zlib' 
require 'open-uri' 

uri = "www.somedomain.com/filename.gz" 
source = open(uri) 
gz = Zlib::GzipReader.new(source) 
result = gz.read 
puts result 

Spero che questo aiuti.

+0

Mavryx: Quando io sto cercando il tuo frammento Sto ottenendo il seguente errore: unzip.rb: 5: variabili locali non definita o metodo 'uri' per # (NameError) – maetthew

+0

@maetthew controlla la riga 4 e assicurati di utilizzare la stessa variabile (uri qui) in entrambe le righe – BurmajaM

10

Anche se Florian's answer è corretto, non tiene conto di tar LongLinks (Provare a estrarre jdk-7u40-linux-i586.tar.gz da oracle: P). Il seguente codice dovrebbe essere in grado di fare questo:

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 
+0

is ': verbose = > falso? necessario? –

+0

No, non volevo che qualcosa fosse stampato nella mia custodia. –

1

Draco, thx per voi snippet. Alcuni codici TAR codificano le directory come percorsi che terminano con '/' - vedi Wiki this. Il catrame examlple è Oracle Server JRE 7u80 for Windows. Questo funziona per loro:

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 
Problemi correlati