How to unzip a file in Ruby on Rails?
Solution 1
I'd use the rubyzip gem. Specifically this part: https://github.com/rubyzip/rubyzip/blob/master/lib/zip/filesystem.rb
It creates an artificial file system in memory mirroring the contents of the zip file. Here's an example based of the example from the docs:
Rubyzip interface changed!!! No need to do require "zip/zip" and Zip prefix in class names removed.
require 'zip'
Zip::File.open("my.zip") do |zipfile|
zipfile.each do |file|
# do something with file
end
end
In your case, just put the name of the uploaded tempfile where my.zip
is in the example, and you can loop through the contents and do your regular operations on them.
Solution 2
From the RubyZip project page:
Rubyzip interface changed!!! No need to do require "zip/zip" and Zip prefix in class names removed.
So, the example code from @ben-lee should be updated to something like this:
require 'zip'
Zip::File.open("my.zip") do |zipfile|
zipfile.each do |file|
# do something with file
end
end
Solution 3
Extract Zip files in Ruby
Once you've installed the rubyzip
gem, you can use this method to extract zip files:
require 'zip'
def extract_zip(file, destination)
FileUtils.mkdir_p(destination)
Zip::File.open(file) do |zip_file|
zip_file.each do |f|
fpath = File.join(destination, f.name)
zip_file.extract(f, fpath) unless File.exist?(fpath)
end
end
end
You use it like this:
extract_zip(zip_path, extract_destination)
Solution 4
Worked for me:
gem install rubyzip
main.rb
require 'zip'
def extract_zip(file, destination)
FileUtils.mkdir_p(destination)
Zip::File.open(file) do |zip_file|
zip_file.each do |f|
fpath = File.join(destination, f.name)
FileUtils.mkdir_p(File.dirname(fpath))
zip_file.extract(f, fpath) unless File.exist?(fpath)
end
end
end
extract_zip('file.zip', 'tmp')
siamii
Updated on July 29, 2022Comments
-
siamii almost 2 years
I'm uploading a file to the server in Ruby on Rails
Normally, it's a text file and I save it in the model as a 'file' field in a Submission ActiveRecord with other fields such as title of submission.. etc.
However, the user can also submit a zip file. In this case the zipfile should unzipped and for each file in the zip a new Submission should be created with the same text fields, but current file.
How can I accomplish this?
I looked at unzip examples on the net, but most use a directory to unzip the files to. I'm not sure if I need that as in the current create method of SubmissionsController, a file object is received and I presume the path to save the file to is automatically generated when the Submission save method is called. So I was thinking that maybe I should unzip the zipfile in memory to get an array of file objects and then create a new Submission with each file object but same fields and then let ActiveRecord generate the file paths for each one when it saves them to the database. I might be wrong here, because I'm kind of new to Rails and Ruby.
-
siamii about 12 yearsI see, so how could I get an array of file objects from the zip file?
-
Ben Lee about 12 years@bizso09, I just updated to show how to loop through the contents. There is also a simple tutorial explaning it here: markhneedham.com/blog/2008/10/02/…
-
siamii about 12 yearsUnfortunately
file
is of type ZipEntry and not of type File, so I cannot save it with Submissions -
Ben Lee about 12 years@bizso09, see the docs and the exmample. You can extract the file from the ZipFile, like
zip_file.extract(f, f_path) unless File.exist?(f_path)
-
0112 about 7 yearsI don't know if it's been changed recently or not, but the
extract
method only takes one arg, and will throw an error if you give it two. -
Jon Burgess over 6 yearsWhat's the reason behind the condition
unless File.exist?(fpath)
? Is that just to replicate behaviour of other tools? -
Akash Agarwal almost 5 years@JonBurgess seems like it's to avoid replacing an existing file with the same name.