How can I generate zip file without saving to the disk with Ruby?
I had a similar problem which I solved using the rubyzip gem and the stringio object.
It turns out that rubyzip provides a method that returns a stringio object: ZipOutputStream.write_buffer
.
You can create the zip file structure as you like using put_next_entry
and write and once you are finished you can rewind the stringio and read the binary data using sysread.
See the following simple example (works for rubyzip 0.9.X)
require 'zip/zip'
stringio = Zip::OutputStream.write_buffer do |zio|
zio.put_next_entry("test.txt")
zio.write "Hello world!"
end
stringio.rewind
binary_data = stringio.sysread
Tested on jruby 1.6.5.1 (ruby-1.9.2-p136) (2011-12-27 1bf37c2) (Java HotSpot(TM) 64-Bit Server VM 1.6.0_29) [Windows Server 2008-amd64-java])
The following example works for rubyzip >= 1.0.0
require 'rubygems'
require 'zip'
stringio = Zip::OutputStream.write_buffer do |zio|
zio.put_next_entry("test.txt")
zio.write "Hello world!"
end
binary_data = stringio.string
Tested on jruby 1.7.22 (1.9.3p551) 2015-08-20 c28f492 on OpenJDK 64-Bit Server VM 1.7.0_79-b14 +jit [linux-amd64] and rubyzip gem 1.1.7
Create zip archive without save archiving file to disk in Ruby
Found!
string_io = Zip::OutputStream.write_buffer do |zos|
zos.put_next_entry(file_name)
zos.write dictionary.join(', ')
end
# Rewind
string_io.rewind
# Write simply to file in bin mode
IO.write("#{file_name}.zip", string_io.sysread)
How can I create a zip file without temporary files in ruby?
See the answer at "How can I generate zip file without saving to the disk with Ruby?"
I adapted your example to demonstrate it works.
require 'zip/zip'
zipname = 'test.zip'
File.delete(zipname) if File.exists?(zipname) #delete previous version
stringio = Zip::ZipOutputStream::write_buffer do |zio|
1.upto(5) do |i| #Just some testfiles with content
zio.put_next_entry("test#{i}.txt") #Filename
zio.write("Testcontent %08i" % i) #generated content
sleep 1 #sleep some time to see the temporary files
end
end
stringio.rewind #reposition buffer pointer to the beginning
File.new("test.zip","wb").write(stringio.sysread) #write buffer to zipfile
Rubyzip download attachments without creating the archive
This is the right syntax that made my code work 100% fine:
# Download zip file of all submission
def download
@submissions = Submission.all
archiveFolder = Rails.root.join('tmp/archive.zip') #Location to save the zip
# Delte .zip folder if it's already there
FileUtils.rm_rf(archiveFolder)
# Open the zipfile
Zip::ZipFile.open(archiveFolder, Zip::ZipFile::CREATE) do |zipfile|
@submissions.each do |filename|
zipfile.add(filename.file_file_name, 'public/files/submissions/files/' + filename.id.to_s + '/original/' + filename.file_file_name)
end
end
# Send the archive as an attachment
send_file(archiveFolder, :type => 'application/zip', :filename => '2016 Submissions.zip', :disposition => 'attachment')
end
rubyzip: open zip, modify it temporary, send to client
in the end i did it like this:
require 'zip'
zip_stream = Zip::OutputStream.write_buffer do |new_zip|
existing_zip = Zip::File.open('existing.zip')
existing_zip.entries.each do |e|
new_zip.put_next_entry(e.name)
new_zip.write e.get_input_stream.read
end
new_zip.put_next_entry 'new_file'
new_zip.print "text"
end
Rubyzip: Export zip file directly to S3 without writing tmpfile to disk?
I think I just found the answer to my question.
It's Zip::ZipOutputStream.write_buffer. I'll check this out and update this answer when I get it working.
Update
It does work. My code is like this now:
compressed_filestream = Zip::ZipOutputStream.write_buffer do |zos|
some_file_list.each do |file|
zos.put_next_entry(file.some_title)
zos.print IO.read(file.path)
end
end # Outputs zipfile as StringIO
s3 = Aws::S3.new(S3_KEY, S3_SECRET)
bucket = Aws::S3::Bucket.create(s3, S3_BUCKET)
compressed_filestream.rewind
bucket.put("#{BUCKET_PATH}/archive.zip", compressed_filestream.read, {}, 'authenticated-read')
The write_buffer
returns a StringIO and needs to rewind the stream first before read
ing it. Now I don't need to create and delete the tmpfile.
I'm just wondering now if write_buffer
would be more memory extensive or heavier than open
? Or is it the other way around?
Processing Zip files in Ruby
Hi I'm using rubyzip library. You can do something like this:
Zip::ZipFile.foreach(file) do |entry|
istream = entry.get_input_stream
data = istream.read
#...
end
Related Topics
How to Convert a Ruby Hash So That All of Its Keys Are Symbols
How to Install the Ruby Ri Documentation
Ruby 1.9 Hash with a Dash in a Key
Why Can't Singleton Methods Be Defined on Symbols or Fixnums
Activerecord::Adapternotspecified Database Configuration Does Not Specify Adapter
Forking a Gem for a Rails Project
Why Does Ruby Have Trueclass and Falseclass Instead of a Single Boolean Class
Rails: How to Use Dependent: :Destroy in Rails
Error: SASS Installation for Windows
Rails Route to Username Instead of Id
Set Attribute Dynamically of Ruby Object
Looping Through an Array with Step
Why Do I Get a Bcrypt-Ruby Gem Install Error
Merging Multi-Dimensional Hashes in Ruby
File Upload with Activeadmin Rails Using Paperclip
How to Get the Name of the Command Called for Usage Prompts in Ruby