I am trying to write a ruby fcgi script which compresses files in a directory on the fly and sends the output blockwise as an http response. It is very important that this compression is done as a stream operation, otherwise the client will get a timeout for huge directories.
I have the following code:
d="/tmp/delivery/"
# send zip header
header(MimeTypes::ZIP)
# pseudocode from here on
IO.open(d) { |fh|
block=fh.readblock(1024)
#send zipped block as http response
print zip_it(block)
}
How do I achieve what I've written as pseudo-ruby in the above listing?
Zip is a streamable format. Zip is a streamable format but it also supports random access through a table of contents (the "central directory") located at the end of the file. This bomb works by overlapping the file offsets in the table of contents.
Ruby | Array zip() function Array#zip() : zip() is a Array class method which Converts any arguments to arrays, then merges elements of self with corresponding elements from each argument. Syntax: Array.zip() Parameter: Array. Return: merges elements of self with corresponding elements from each argument.
Tokland's idea of using the external zip command works pretty well. Here's a quick snippet that should work with Ruby 1.9 on Linux or similar environments. It uses an array parameter to popen()
to avoid any shell quoting issues and sysread
/syswrite
to avoid buffering. You could display a status message in the empty rescue
block if you like -- or you could use read
and write
, though I haven't tested those.
#! usr/bin/env ruby
d = '/tmp/delivery'
output = $stdout
IO.popen(['/usr/bin/zip', '-', d]) do |zip_output|
begin
while buf = zip_output.sysread(1024)
output.syswrite(buf)
end
rescue EOFError
end
end
AFAYK Zip format is not streamable, at end of compression it writes something in the file header.
gz or tar.gz is better option.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With