使用rubyzip将文件和嵌套目录添加到zipoutputstream

我正在努力让rubyzip将目录附加到zipoutputstream。 (我想要输出流,所以我可以从rails控制器发送它)。 我的代码遵循以下示例:

Using rubyzip to create zip files on the fly

当修改为包含要添加的文件列表中的目录时,我收到以下错误:

任何帮助将不胜感激。

UPDATE

在尝试了一些解决方案后,我在zipruby上获得了最大的成功,它有一个干净的api和很好的例子:http: //zipruby.rubyforge.org/ 。

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 

OOOOOuuhhh …你绝对想要ZIPPY。 它是一个Rails插件,它抽象了rubyzip中的许多复杂性,并允许你创建你正在谈论的内容,包括目录(从我记得)。

干得好:

http://github.com/toretore/zippy

并直接来自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 

编辑 :修改每个用户评论:

嗯……使用Zippy的整个目标是使用ruby拉链更加容易。 雅可能想要第二次(或第一次)看……

以下是如何使用目录创建目录:

 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 => ... 

Zippy将为此工作。 可能有一种更酷的方法来做到这一点,但由于基本上没有文档,这就是我想出的用于在Rakefile中以Zippy递归复制目录。 这个Rakefile用在Rails环境中,所以我把gem需求放在我的Gemfile中:

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

这是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 

现在我可以像这样使用它:

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

它将生成my.zip ,其中包含一个名为“my”的内部目录,其中包含所选文件和目录的副本。

我能够使用原始文章中使用的相同ZipOutputStream来获取目录。

我所要做的就是在调用zos.put_next_entry时添加目录。

例如:

 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 

我刚刚将zos.put_next_entry('some-funny-name.jpg') zos.put_next_entry('myfolder/some-funny-name.jpg') zos.put_next_entry('some-funny-name.jpg')更改为zos.put_next_entry('myfolder/some-funny-name.jpg') ,生成的zipfile有一个名为myfolder的嵌套文件夹,其中包含这些文件。