ユーザーごとに中身が別々のzipをダウンロードさせたいんだけど、いちいちzipファイルをディスクに保存したくないような時。
以下の例ではziprubyのZip::Archive.open_bufferメソッドで特定のディレクトリ内のファイルをまとめて圧縮して送信している。
ファイル名とファイル本体のバッファを保持しているハッシュの中身をユーザーごとにカスタマイズすれば、
好きなようにzipの中身をきめて、生成してダウンロードさせることができる。
Zip::Archive.open_bufferはメモリ上のバッファに書き出しが終わるまでレスポンスが送信されないのがちょっと難点で、
巨大すぎるファイルの圧縮だと時間が掛かり過ぎてタイムアウトになってしまうことがあるかもしれない。
メモリではなくTCPsocketにできたところから直接書き出しできれば多少はマシになると思われるので、
超巨大ファイルを圧縮転送したいひとはチャレンジしてやりかた教えてください。
参考までに、総容量100MB~200MB程度だと、ダウンロードして保存するダイアログの表示がちょっともたつく程度でタイムアウトまではしませんでした。
require 'rubygems' require 'sinatra' require 'zipruby' get '/download.zip' do dir = '/home/sinatra/myapp/public/zip' files = [] Dir::foreach(dir) {|f| next if f == "." or f == ".." or f == ".gitignore" files.push dirpath + "/" + f } file_buffers = Hash.new files.each do |path| # fileをbufferにためる filename = File::basename(path) file = open(path, "rb") file_buffers.store filename, file.read file.close # ファイルを閉じる end # オンメモリでzipファイルを生成 zip_buffer = '' Zip::Archive.open_buffer(zip_buffer, Zip::CREATE, Zip::NO_COMPRESSION) do |zipb| # fileのbufferをzipのbufferにつっこんでいく file_buffers.each_pair do |filename, buf| zipb.add_buffer(filename, buf) end end # メモリ上のデータを送信 content_type 'application/zip' attachment 'download.zip' zip_buffer end