2009-06-08 18 views
7

Estoy intentando descomprimir un archivo con varios archivos que pueden existir o no en el directorio de destino. Parece que el comportamiento predeterminado es lanzar una excepción si el archivo ya existe.Cómo sobrescribir archivos existentes usando Rubyzip lib

¿Cómo descomprimo en un directorio y simplemente sobrescribo los archivos existentes?

Aquí está mi código:

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 

Respuesta

12

Parece que el extracto() toma un bloque opcional (onExistsProc) que le permite determinar qué hacer con el archivo si ya existe - regresa fiel a sobrescribir , falso para levantar una excepción.

Si quería simplemente sobrescribir todos los archivos existentes, se podría hacer:

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

Si usted quiere hacer algo de lógica más compleja para manejar entradas específicas de manera diferente, que puede hacer:

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

EDIT: respuesta fija: como señaló Ingmar Hamer, mi respuesta original pasó el bloque como un parámetro cuando se esperaba usando la sintaxis anterior.

+0

Esta respuesta en realidad no funciona como se publicó. Vea la respuesta publicada por Ingmar Hamer y dele un punto para su corrección. –

1

Editar: Modificado código para eliminar archivo de destino si es que existe de antemano.

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') 

Editar: código modificado para eliminar el directorio de destino si existe de antemano.

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') 

Aquí es 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

Gracias por la respuesta, pero parece que esto no sobrescribirá un archivo existente. Simplemente se saltará si existe. – digitalsanctum

+0

... de hecho omite archivos que existen. Qué tonto soy por no haber probado ese caso de uso en particular antes de publicarlo. Mis disculpas. Por favor, vea mi versión editada que eliminará el directorio de destino si existe de antemano. – bernie

+0

Y mi segunda solución tampoco era óptima. Debido a que eliminar el directorio completo probablemente sea raramente recomendable; pero creo que la tercera vez es un encanto: agregué un poco de código para eliminar el archivo si existe antes de escribir el nuevo archivo. – bernie

14

en salvar a otros el problema:

El comando de extracción en respuesta 2 es incorrecta:

El tercer parámetro (proc) se especifica satisfechas con un símbolo de unión, es decir, rubí espera que sea en {} - entre paréntesis después de la llamada al método como este:

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

o (si necesita una lógica más compleja)

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

Si utiliza el ejemplo dado en la publicación n. ° 2 obtendrá un error de "argumentos inválidos (3 por 2)" ...

+0

Gracias. Soy nuevo para Ruby y me golpeé la cabeza contra esta pared en particular durante una hora. –

0

Este link here proporciona un buen ejemplo que he verificado. Solo necesita tener un 'fileutils' requerido.

Cuestiones relacionadas