Mark Needham

Thoughts on Software Development

Ruby: Unzipping a file using rubyzip

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

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • HackerNews
  • StumbleUpon
  • Twitter

Written by Mark Needham

October 2nd, 2008 at 12:04 am

Posted in Ruby

Tagged with ,

7 Responses to 'Ruby: Unzipping a file using rubyzip'

Subscribe to comments with RSS or TrackBack to 'Ruby: Unzipping a file using rubyzip'.

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

  2. "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

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

    unzips any file on linux

    Greg

    3 Oct 08 at 8:36 am

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

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

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

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

Leave a Reply