2009-06-08 11 views
7

Sto tentando di decomprimere un file con diversi file che potrebbero o non possono già esistere nella directory di destinazione. Sembra che il comportamento predefinito sia quello di generare un'eccezione se il file esiste già.Come sovrascrivere i file esistenti utilizzando Rubyzip lib

Come si decomprime in una directory e si sovrascrive semplicemente i file esistenti?

Ecco il mio codice:

begin 
    Zip::ZipFile.open(source) do |zipfile| 
    dir = zipfile.dir 
    dir.entries('.').each do |entry| 
     zipfile.extract(entry, "#{target}/#{entry}") 
    end 
    end 
rescue Exception => e 
    log_error("Error unzipping file: #{local_zip} #{e.to_s}") 
end 

risposta

12

Sembra che l'estratto() prende un blocco opzionale (onExistsProc) che consente di determinare cosa fare con il file se esiste già - ritorni vero per sovrascrivere , falso per sollevare un'eccezione.

Se si voleva sovrascrivere semplicemente tutti i file esistenti, si potrebbe fare:

zipfile.extract(entry, "#{target}/#{entry}") { true } 

Se si vuole fare un po 'logica più complessa da gestire voci specifiche in modo diverso, si può fare:

zipfile.extract(entry, "#{target}/#{entry}") {|entry, path| some_logic(entry, path) } 

EDIT: risposta fissa - come indicato da Ingmar Hamer, la mia risposta originale ha superato il blocco come parametro quando è previsto utilizzando la sintassi precedente.

+0

Questa risposta in realtà non funziona come postata. Vedi la risposta postata da Ingmar Hamer e dagli un punto per la sua correzione. –

1

Edit: Modificato codice per rimuovere file di destinazione, se esiste in anticipo.

require 'rubygems' 
require 'fileutils' 
require 'zip/zip' 

def unzip_file(file, destination) 
    Zip::ZipFile.open(file) { |zip_file| 
    zip_file.each { |f| 
    f_path=File.join(destination, f.name) 
    if File.exist?(f_path) then 
     FileUtils.rm_rf f_path 
    end 
    FileUtils.mkdir_p(File.dirname(f_path)) 
    zip_file.extract(f, f_path) 
    } 
    } 
end 

unzip_file('/path/to/file.zip', '/unzip/target/dir') 

Modifica: codice modificato per rimuovere la directory di destinazione se esistente in precedenza.

require 'rubygems' 
require 'fileutils' 
require 'zip/zip' 

def unzip_file(file, destination) 
    if File.exist?(destination) then 
    FileUtils.rm_rf destination 
    end 
    Zip::ZipFile.open(file) { |zip_file| 
    zip_file.each { |f| 
    f_path=File.join(destination, f.name) 
    FileUtils.mkdir_p(File.dirname(f_path)) 
    zip_file.extract(f, f_path) 
    } 
    } 
end 

unzip_file('/path/to/file.zip', '/unzip/target/dir') 

Ecco the original code from Mark Needham:

require 'rubygems' 
require 'fileutils' 
require 'zip/zip' 

def unzip_file(file, destination) 
    Zip::ZipFile.open(file) { |zip_file| 
    zip_file.each { |f| 
    f_path=File.join(destination, f.name) 
    FileUtils.mkdir_p(File.dirname(f_path)) 
    zip_file.extract(f, f_path) unless File.exist?(f_path) 
    } 
    } 
end 

unzip_file('/path/to/file.zip', '/unzip/target/dir') 
+0

Grazie per la risposta, ma sembra che questo non sovrascriverà un file esistente. Salterà semplicemente se esiste. – digitalsanctum

+0

... in effetti salta i file esistenti. Che sciocco da parte mia non testare quel particolare caso d'uso prima di postare. Mie scuse. Si prega di consultare la mia versione modificata che rimuoverà la directory di destinazione se esistente in precedenza. – bernie

+0

E la mia seconda soluzione era anche subottimale. Perché l'eliminazione dell'intera directory è probabilmente raramente consigliabile; ma credo che la terza volta sia un incantesimo: ho aggiunto un po 'di codice per cancellare il file, se esiste prima di scrivere il nuovo file. – bernie

14

solo per salvare gli altri il problema:

Il comando estratto in risposta 2 non è corretto:

Il terzo parametro (proc) viene specificato addebbitato una e commerciale, il che significa rubino si aspetta che sia in {} - parentesi dopo la chiamata al metodo come questo:

zipfile.extract(entry, "#{target}/#{entry}"){ true } 

o (se avete bisogno di una logica più complessa)

zipfile.extract(entry, "#{target}/#{entry}") {|entry, path| some_logic(entry, path) } 

Se si utilizza l'esempio riportato nel post # 2, verrà visualizzato un errore "argomenti non valido (3 per 2)" ...

+0

Grazie. Sono nuovo di Ruby e ho battuto la testa contro questo particolare muro per un'ora. –

0

Questo link here fornisce un buon esempio di cui ho verificato i lavori. Basta che ci sia bisogno di aggiungere "fileutils".

Problemi correlati