kdt*_*kdt 16 streaming zip ruby-on-rails
我需要通过zip文件从我的数据库中提供一些数据,然后即时流式传输:
我知道我可以做流生成zip文件使用filesystemk ZipOutputStream
作为这里.我也知道,我能做的设置流从轨控制器输出response_body
到Proc
作为这里.我需要(我认为)是一种将这两件事融合在一起的方法.我可以让铁杆响应来自ZipOutputStream
吗?我可以ZipOutputStream
给我增量的数据块,我可以提供给我response_body
Proc
吗?或者还有另一种方式吗?
fri*_*ngd 11
https://github.com/fringd/zipline
所以jo5h的答案在rails 3.1.1中对我不起作用
我找到了一个有帮助的YouTube视频.
http://www.youtube.com/watch?v=K0XvnspdPsc
它的关键是创建一个对每个响应的对象......这就是我所做的:
class ZipGenerator
def initialize(model)
@model = model
end
def each( &block )
output = Object.new
output.define_singleton_method :tell, Proc.new { 0 }
output.define_singleton_method :pos=, Proc.new { |x| 0 }
output.define_singleton_method :<<, Proc.new { |x| block.call(x) }
output.define_singleton_method :close, Proc.new { nil }
Zip::IoZip.open(output) do |zip|
@model.attachments.all.each do |attachment|
zip.put_next_entry "#{attachment.name}.pdf"
file = attachment.file.file.send :file
file = File.open(file) if file.is_a? String
while buffer = file.read(2048)
zip << buffer
end
end
end
sleep 10
end
end
def getzip
self.response_body = ZipGenerator.new(@model)
#this is a hack to preven middleware from buffering
headers['Last-Modified'] = Time.now.to_s
end
Run Code Online (Sandbox Code Playgroud)
编辑:
上面的解决方案实际上没有工作......问题是rubyzip需要跳转文件来重写条目的标题.特别是它需要在写入数据之前写入压缩大小.这在真正的流媒体情况下是不可能的......所以最终这个任务可能是不可能的.有可能一次缓冲整个文件,但这似乎不值得.最终我只是写了一个tmp文件...在heroku上我可以写入Rails.root/tmp较少的即时反馈,并不理想,但是必要.
另一个编辑:
我最近得到了另一个想法...如果我们不压缩它们,我们可以知道文件的压缩大小.计划是这样的:
ZipStreamOutput类的子类如下:
我还没有尝试过这个,但会报告是否有任何成功.
好的最后编辑:
在zip标准中:http://en.wikipedia.org/wiki/Zip_(file_format)#File_headers
他们提到有一点你可以翻转放大小,压缩大小和文件后的crc.所以我的新计划是将zipoutput流子类化为它
此外,我需要得到所有的黑客,以便在固定的铁路输出流...
无论如何这一切都奏效了!
这是一颗宝石!
https://github.com/fringd/zipline
小智 3
我有类似的问题。我不需要直接流式传输,但只有第一种情况不想写入临时文件。您可以轻松修改 ZipOutputStream 以接受 IO 对象而不仅仅是文件名。
module Zip
class IOOutputStream < ZipOutputStream
def initialize io
super '-'
@outputStream = io
end
def stream
@outputStream
end
end
end
Run Code Online (Sandbox Code Playgroud)
从那里开始,只需在您的 Proc 中使用新的 Zip::IOOutputStream 即可。在你的控制器中,你可能会这样做:
self.response_body = proc do |response, output|
Zip::IOOutputStream.open(output) do |zip|
my_files.each do |file|
zip.put_next_entry file
zip << IO.read file
end
end
end
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
10323 次 |
最近记录: |