Mark Needham

Thoughts on Software Development

Ruby: Unzipping a file using rubyzip

with 9 comments

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.

Be Sociable, Share!

Written by Mark Needham

October 2nd, 2008 at 12:04 am

Posted in Ruby

Tagged with ,

  • http://www.crudvision.com Lisa Seelye

    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.

  • Scott

    “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.

  • Greg

    http://blog.thoughtfolder.com/code/e.rb

    unzips any file on linux

  • http://7fff.com John

    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

  • http://pragmatig.wordpress.com grosser

    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/

  • http://www.pixallent.com Michael Larkin

    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.

  • Aninda

    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?

  • Manish Nautiyal

    Thanks you save my day :)

  • Foo

    Out of date.. A shame since it has so many hits it’s at the top of Google search so people click on it so it keeps getting so many hits.. See where this is going? Be nice if things like this had a time-to-live of a couple of years or so and then would just disappear. The Internet never forgets… unfortunately.