Ruby: Unzipping a file using rubyzip
In the world of Ruby I've been working on a script which needs to unzip a file and then run an installer which is only available after unpacking it.
We've been using the rubyzip gem to do so but so far it hasn't felt intuitive to me coming from the Java/C# world.
ZipFile is the class we need to use and at first glance I had thought that it would be possible to just pass the zip file name to the 'extract' method and have it do all the work for me!
Turns out you actually need to open the zip file and then create the directory location for each file in the zip before extracting them all individually.
We eventually ended up with this little method:
1 2 3 4 5 6 7 8 9 10 11 12 | require 'rubygems' require 'zip/zip' def unzip_file (file, destination) Zip::ZipFile.open(file) { |zip_file| zip_file.each { |f| f_path=File.join(destination, f.name) FileUtils.mkdir_p(File.dirname(f_path)) zip_file.extract(f, f_path) unless File.exist?(f_path) } } end |
Which we can then call with the zip file and the destination where we want to unzip the file.
1 | unzip_file("my.zip", "marks_zip") |
Is there a better way to do this? It feels a bit clunky to me at the moment.
You're better off just piping to your local unzip binary. The rubyzip library isn't very well made (even though it seems like the only thing we have) and the native unzip binary is just so powerful that it makes sense to harness it, even though calling a binary from ruby isn't exactly kosher.
Lisa Seelye
2 Oct 08 at 6:36 am
"calling a binary from ruby isn't exactly kosher". Sure it is, just make sure to properly check stdout and stderr as needed to make sure everything went as planned.
Scott
2 Oct 08 at 3:24 pm
http://blog.thoughtfolder.com/code/e.rb
unzips any file on linux
Greg
3 Oct 08 at 8:36 am
Mark, another problem is when you want to make a ZIP on, say, a Windows system that doesn't have Cygwin. In other words, no native ZIP. Without a native ZIP (that understand -r) you also can't do rake package (unless things have changed recently). Here's a hack at making a ZIP from Ruby. I would love to have a more robust version of this.
# Drop-in for zip for those who don't have one on their systems.
# For this, you will first need to
# gem install rubyzip
#
require 'rubygems'
require 'zip/zip'
recursive = false
if ARGV[0] == '-r'
recursive = true
ARGV.shift
end
archive = ARGV.shift
ARGV.each do |arg|
files = recursive ? Dir[ arg + '/**/*.*' ] : [arg]
files.each do |f|
Zip::ZipFile.open(archive, Zip::ZipFile::CREATE) do |z|
begin
z.remove(f)
rescue
end
entry = f.dup
# blech
if (entry[0..1] == './')
entry = entry[2..-1]
end
z.add(entry, f)
puts " adding #{f}"
end
end
end
John
7 Oct 08 at 3:00 am
here comes the reverse example:
packing a folder to a zip file
http://pragmatig.wordpress.com/2009/02/04/compressing-a-folder-to-a-zip-archive-with-ruby/
grosser
4 Feb 09 at 4:59 pm
Thanks! This was a great example.
I added a next unless f.file? to skip directories (they're created automatically by the mkdir_p call) as well as filtering out the junk files like .DS_STORE, Thumbs.db, __MAC_OSX and such.
Michael Larkin
9 Jul 09 at 1:55 pm
Hi Mark,
Thanks for your example. I was wondering how you would deal with the scenario that you have a zip file within a zip file?
Aninda
20 Jun 10 at 6:05 pm