2010-12-03 50 views
5

我有一個Ruby應用程序,我需要修改一個現有的zip文件。如何修改內存中的zip文件?

我想在內存中構建壓縮文件,並在不將文件寫入文件系統的情況下將字節流回。如果我最終在Heroku上託管它,我不認爲我可以寫入文件系統。有誰知道一種方法來做到這一點?

我看着Zip::ZipFile,但它看起來總是想寫入文件系統。我想是「基於java的實現」我可以得到壓縮文件的字節,你可以在java中完成,但我沒有辦法做到這一點。


編輯:

我所問的是基本相同的,但對Ruby的,而不是Python的: Function to create in-memory zip file and return as http response

回答

3

這裏有一個blog post,與此問題涉及。它使用Tempfile,對我來說似乎是一個很好的解決方案(儘管通讀了一些有用的額外討論的評論)。

一個例子,從柱:

def download_zip(image_list) 
    if !image_list.blank? 
    file_name = "pictures.zip" 
    t = Tempfile.new("my-temp-filename-#{Time.now}") 
    Zip::ZipOutputStream.open(t.path) do |z| 
     image_list.each do |img| 
     title = img.title 
     title += ".jpg" unless title.end_with?(".jpg") 
     z.put_next_entry(title) 
     z.print IO.read(img.path) 
     end 
    end 
    send_file t.path, :type => 'application/zip', 
         :disposition => 'attachment', 
         :filename => file_name 
    t.close 
    end 
end 

該溶液should play nice with Heroku

+0

是不是Tempfile創建一個文件? – 2010-12-03 23:31:49

1

您可以隨時修補Zip :: ZipFile的newopen方法以允許使用StringIO句柄,然後將您的I/O直接寫入內存。

1

要在這裏提出一個我自己的問題的答案,我認爲更適合我想要做的事情。這種方法確實沒有文件(沒有臨時文件)。

由於ZipFile進行了擴展,並且實際上只是ZipCentralDirectory中的一組便捷方法,因此您可以直接使用ZipCentralDirectory而不是ZipFile。這將允許您使用IO流來創建和編寫zip文件。另外扔在使用StringIO這種,你可以從一個字符串做:

# load a zip file from a URL into a string 
    resp = Net::HTTP.new("www.somewhere.com", 80).get("/some.zip") 
    zip_as_string = response.body 

    # open as a zip 
    zip = Zip::ZipCentralDirectory.read_from_stream(StringIO.new(zip_as_string)) 

    # work with the zip file. 
    # i just output the names of each entry to show that it was read correctly 
    zip.each { |zf| puts zf.name } 

    # write zip back to an output stream 
    out = StringIO.new 
    zip.write_to_stream(out) 

    # use 'out' or 'out.string' to do whatever with the resulting zip file. 
    out.string 

更新:

這實際上並沒有在所有的工作。它將編寫一個可讀的zip文件,但只有zip文件的「目錄」。所有內部文件都是0長度。進一步深入研究Zip實現,它看起來像只保存內存中的zip條目'元數據',並且它返回到底層文件以讀取其他所有內容。基於此,看起來不可能在不寫入文件系統的情況下使用Zip實現。

4

有同樣的問題,一定要得到它關閉文件和讀取數據和流作爲SEND_DATA

然後發現,在Heroku上工作正常,並可以在內存中緩存處理另一個庫工作:這是zipruby (不是rubyzip)。

buffer = '' 
Zip::Archive.open_buffer(buffer, Zip::CREATE) do |archive| 
    files.each do |wood, report| 
    title = wood.abbreviation+".txt" 
    archive.add_buffer(title, report); 
    end 
end 
file_name = "dimter_#{@offer.customerName}_#{Time.now.strftime("%m%d%Y_%H%M")}.zip" 
send_data buffer, :type => 'application/zip', :disposition => 'attachment', :filename => file_name