2010-02-24 12 views
7

Ho difficoltà a ottenere rubyzip per aggiungere directory a un file zipoutput. (Voglio il flusso di output in modo che possa inviarlo da un controller di rotaie). Il mio codice segue questo esempio:Utilizzo di rubyzip per aggiungere file e directory nidificate a uno zipoutputstream

http://info.michael-simons.eu/2008/01/21/using-rubyzip-to-create-zip-files-on-the-fly/

Quando modificato per includere le directory nella lista dei file da aggiungere ricevo il seguente errore:

Qualsiasi aiuto sarebbe molto apprezzato.

UPDATE

Dopo aver provato una serie di soluzioni che ho avuto più successo con zipruby che ha un api pulito e buoni esempi: http://zipruby.rubyforge.org/.

+0

Ottimo lavoro per trovare zipruby, ho salvato la giornata! –

risposta

5

OOOOOuuuhh ... VUOI SICURAMENTE ZIPPY. È un plug-in Rails che astrae gran parte della complessità in rubyzip e consente di creare ciò di cui si sta parlando, comprese le directory (da ciò che ricordo).

Qui si va:

http://github.com/toretore/zippy

E direttamente dal sito Zippy:

Example controller: 
def show 
    @gallery = Gallery.find(params[:id]) 
    respond_to do |format| 
    format.html 
    format.zip 
    end 
end 

Example view: 
zip['description.txt'] = @gallery.description 
@gallery.photos.each do |photo| 
    zip["photo_#{photo.id}.png"] = File.open(photo.url) 
end 

modificare: rettificativo per Utente:

Hmm ... tutto L'obiettivo di usare Zippy è rendere molto più facile l'uso di ruby ​​zip. Ya potrebbe desiderare di prendere una seconda (o prima) sembrano ...

Ecco come fare una directory con directory:

some_var = Zippy.open('awsum.zip') do |zip| 
    %w{dir_a dir_b dir_c diri}.each do |dir| 
    zip["bin/#{dir}/"] 
    end 
end 

... 

send_file some_var, :file_name => ... 
+0

Grazie a questo sembra buono ma i documenti sono un po 'timidi e non ho il tempo di scavare attraverso la fonte proprio ora. Quindi, ad esempio, come dovrei creare un flusso zip e aggiungere una directory di directory? Inoltre, ho bisogno di usare sendfile piuttosto che un tipo mime personalizzato. Grazie. – fturtle

+0

risolto la risposta nel caso in cui sei interessato. – btelles

+0

Scusa, ma ho trovato questo gioiello un lavoro piuttosto duro. Ci sono un paio di altri che cercherò di riprodurre in streaming un nuovo zip nel modo che voglio. – fturtle

9
Zip::ZipFile.open(path, Zip::ZipFile::CREATE) do |zip| 
    songs.each do |song| 
    zip.add "record/#{song.title.parameterize}.mp3", song.file.to_file.path 
    end 
end 
+0

È semplice e funziona – benjineer

3

Zippy lavorerà per questo. Potrebbe esserci un modo più efficace per farlo, ma poiché non ci sono essenzialmente documenti, ecco cosa mi è venuto in mente per copiare ricorsivamente le directory con Zippy in un Rakefile. Questo Rakefile viene utilizzato in un ambiente Rails così ho messo requisiti gemma nel mio Gemfile:

#Gemfile 
source 'http://rubygems.org' 
gem 'rails' 
gem 'zippy' 

E questo è il Rakefile

#Rakefile 
def add_file(zippyfile, dst_dir, f) 
    zippyfile["#{dst_dir}/#{f}"] = File.open(f) 
end 

def add_dir(zippyfile, dst_dir, d) 
    glob = "#{d}/**/*" 
    FileList.new(glob).each { |f| 
    if (File.file?(f)) 
     add_file zippyfile, dst_dir, f 
    end 
    } 
end 

task :myzip do 
    Zippy.create 'my.zip' do |z| 
    add_dir z, 'my', 'app' 
    add_dir z, 'my', 'config' 
    #... 
    add_file z, 'my', 'config.ru' 
    add_file z, 'my', 'Gemfile' 
    #... 
    end 
end 

Ora posso usare in questo modo:

C:\> cd my 
C:\my> rake myzip 

e produrrà my.zip che contiene una directory interna denominata "mia" con copie di file e directory selezionati.

2

Sono stato in grado di ottenere le directory che funzionano con lo stesso ZipOutputStream utilizzato nello original article.

Tutto quello che dovevo fare era aggiungere la directory quando si chiama zos.put_next_entry.

Ad esempio:

require 'zip/zip' 
require 'zip/zipfilesystem' 

t = Tempfile.new("some-weird-temp-file-basename-#{request.remote_ip}") 
# Give the path of the temp file to the zip outputstream, it won't try to open it as an archive. 
Zip::ZipOutputStream.open(t.path) do |zos| 
    some_file_list.each do |file| 
    # Create a new entry with some arbitrary name 
    zos.put_next_entry("myfolder/some-funny-name.jpg") # Added myfolder/ 
    # Add the contents of the file, don't read the stuff linewise if its binary, instead use direct IO 
    zos.print IO.read(file.path) 
    end 
end 
# End of the block automatically closes the file. 
# Send it using the right mime type, with a download window and some nice file name. 
send_file t.path, :type => 'application/zip', :disposition => 'attachment', :filename => "some-brilliant-file-name.zip" 
# The temp file will be deleted some time... 
t.close 

ho appena cambiato zos.put_next_entry('some-funny-name.jpg') a zos.put_next_entry('myfolder/some-funny-name.jpg'), e il file zip risultante aveva una cartella annidata chiamata myfolder che conteneva i file.

+1

Il tuo metodo ha funzionato bene, grazie! Sono quasi passato a '' 'zipruby''', ma non sembra più essere mantenuto. – rkallensee

Problemi correlati