57

Zlib::GzipReader can take "an IO, or IO-like, object." as it's input, as stated in docs.

Zlib::GzipReader.open('hoge.gz') {|gz|
  print gz.read
}

File.open('hoge.gz') do |f|
  gz = Zlib::GzipReader.new(f)
  print gz.read
  gz.close
end

How should I ungzip a string?

Fluffy
  • 27,504
  • 41
  • 151
  • 234

9 Answers9

130

The above method didn't work for me.
I kept getting incorrect header check (Zlib::DataError) error. Apparently it assumes you have a header by default, which may not always be the case.

The work around that I implemented was:

require 'zlib'
require 'stringio'
gz = Zlib::GzipReader.new(StringIO.new(resp.body.to_s))    
uncompressed_string = gz.read
rogerdpack
  • 62,887
  • 36
  • 269
  • 388
Garth
  • 1,406
  • 2
  • 9
  • 9
19

Zlib by default asumes that your compressed data contains a header. If your data does NOT contain a header it will fail by raising a Zlib::DataError.

You can tell Zlib to assume the data has no header via the following workaround:

def inflate(string)
  zstream = Zlib::Inflate.new(-Zlib::MAX_WBITS)
  buf = zstream.inflate(string)
  zstream.finish
  zstream.close
  buf
end
16

You need Zlib::Inflate for decompression of a string and Zlib::Deflate for compression

  def inflate(string)
    zstream = Zlib::Inflate.new
    buf = zstream.inflate(string)
    zstream.finish
    zstream.close
    buf
  end
dimus
  • 8,712
  • 10
  • 45
  • 56
16

In Rails you can use:

  • ActiveSupport::Gzip.compress("my string")
  • ActiveSupport::Gzip.decompress().
Tyler
  • 512
  • 6
  • 8
7

zstream = Zlib::Inflate.new(16+Zlib::MAX_WBITS)

BearPy
  • 322
  • 5
  • 7
  • 2
    Nice one. From [the docs](http://www.ruby-doc.org/stdlib-2.1.5/libdoc/zlib/rdoc/Zlib/Inflate.html) "or add 16 to decode only the gzip format (a Zlib::DataError will be raised for a non-gzip stream)" – ian Dec 10 '14 at 13:39
5

Using (-Zlib::MAX_WBITS), I got ERROR: invalid code lengths set and ERROR: invalid block type
The only following works for me, too.

Zlib::GzipReader.new(StringIO.new(response_body)).read
Nakilon
  • 34,866
  • 14
  • 107
  • 142
john
  • 51
  • 1
  • 2
3

We don't need any extra parameters these days. There are deflate and inflate class methods which allow for quick oneliners like these:

>> data = "Hello, Zlib!"
>> compressed = Zlib::Deflate.deflate(data)
=> "x\234\363H\315\311\311\327Q\210\312\311LR\004\000\032\305\003\363"
>> uncompressed = Zlib::Inflate.inflate(compressed)
=> "Hello, Zlib!"

I think it answers the question "How should I ungzip a string?" the best. :)

Alex Fortuna
  • 1,223
  • 12
  • 16
  • 4
    If you compress and decompress then this will be fine, but it will not be gzip compressed. Just running Zlib::Inflate.inflate(compressed) on gzip compressed data will assume the wrong compression and throw a "incorrect header check" exception. – philwhln Nov 04 '12 at 22:20
3

I used the answer above to use a Zlib::Deflate

I kept getting broken files (for small files) and it took many hours to figure out that the problem can be fixed using:

buf = zstream.deflate(string,Zlib::FINISH)

without the the zstream.finish line!

def self.deflate(string)
    zstream = Zlib::Deflate.new
    buf = zstream.deflate(string,Zlib::FINISH)
    zstream.close
    buf
end
Abdo
  • 13,549
  • 10
  • 79
  • 98
3

To gunzip content, use following code (tested on 1.9.2)

Zlib::GzipReader.new(StringIO.new(content), :external_encoding => content.encoding).read

Beware of encoding problems

pinguin666
  • 466
  • 3
  • 4