2010-02-24 6 views
7

Ich habe Probleme mit rubyzip, um Verzeichnisse an einen zipoutputstream anzuhängen. (Ich möchte den Ausgabestrom, damit ich es von einem Schienen-Controller senden kann). Mein Code folgt diesem Beispiel:Verwenden von rubyzip zum Hinzufügen von Dateien und verschachtelten Verzeichnissen zu einem zipoutputstream

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

Wenn modifizierte Verzeichnisse in der Liste der Dateien enthalten ich folgende Fehlermeldung erhalten hinzuzufügen:

Jede Hilfe wäre sehr dankbar.

UPDATE

Nach einer Reihe von Lösungen versuchen, hatte ich mit zipruby bestem Erfolg, der eine saubere api und gute Beispiele hat: http://zipruby.rubyforge.org/.

+0

Großartige Arbeit, Zipruby zu finden, rettete meinen Tag! –

Antwort

5

OOOOOuuuhh ... Sie wollen unbedingt ZIPPY. Es ist ein Rails-Plugin, das einen Großteil der Komplexität in Rubyzip abstrahiert, und Sie können erstellen, worüber Sie sprechen, einschließlich Verzeichnisse (von was ich mich erinnere).

Hier gehen Sie:

http://github.com/toretore/zippy

Und direkt von der flinke Website:

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 

bearbeiten: Berichtigungs pro Benutzer Kommentar:

Hmm ... das ganze Ziel von Zippy ist es, Ruby Zip viel einfacher zu machen. Ya könnte einen zweiten (oder ersten) nehmen wollen sehen ...

Hier ist, wie ein Verzeichnis mit Verzeichnissen zu machen:

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

Danke, das sieht gut aus, aber die Docs sind etwas schüchtern und ich habe gerade keine Zeit, die Quelle zu durchforsten. Also zum Beispiel, wie würde ich einen Zip-Stream erstellen und ein Verzeichnis von Verzeichnissen hinzufügen? Außerdem muss ich Sendfile anstelle eines benutzerdefinierten Mime-Typs verwenden. Vielen Dank. – fturtle

+0

die Antwort repariert, falls Sie interessiert sind. – btelles

+0

Sorry, aber ich habe dieses Juwel als ziemlich harte Arbeit empfunden. Es gibt ein paar andere, die ich versuchen werde, die eine neu erstellte Zip in der Art, wie ich will, streamen kann. – 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

Es ist einfach und es funktioniert – benjineer

3

Zippy wird für diese Arbeit. Es mag einen cooleren Weg geben, dies zu tun, aber da es im Grunde keine Docs gibt, habe ich mir das zum rekursiven Kopieren von Verzeichnissen mit Zippy in einem Rakefile ausgedacht. Diese Rakefile in einer Rails-Umgebung verwendet, damit ich gem Anforderungen in meinem Gemfile setzen:

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

Und das ist die 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 

Jetzt habe ich es wie folgt verwenden:

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

und es wird my.zip produzieren, die ein inneres Verzeichnis namens 'my' mit Kopien ausgewählter Dateien und Verzeichnisse enthält.

2

Ich konnte Verzeichnisse mit der gleichen ZipOutputStream in der original article verwendet arbeiten.

Alles, was ich tun musste, war das Verzeichnis beim Aufruf zos.put_next_entry.

Zum Beispiel:

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 

Ich habe gerade zos.put_next_entry('some-funny-name.jpg') zu zos.put_next_entry('myfolder/some-funny-name.jpg') und die resultierende zipfile hatte einen verschachtelten Ordner namens myfolder, die die Dateien enthalten sind.

+1

Ihre Methode hat gut funktioniert, danke! Ich bin fast zu '' 'zipruby''' gewechselt, aber es scheint nicht mehr gepflegt zu werden. – rkallensee

Verwandte Themen