Gzip compression and decompression with streaming support
gem install philiprehberger-gzip_kitGzip compression and decompression with streaming support
Add to your Gemfile:
gem "philiprehberger-gzip_kit"
Or install directly:
gem install philiprehberger-gzip_kit
require "philiprehberger/gzip_kit"
compressed = Philiprehberger::GzipKit.compress("Hello, world!")
original = Philiprehberger::GzipKit.decompress(compressed)
require "philiprehberger/gzip_kit"
# Fast compression
fast = Philiprehberger::GzipKit.compress(data, level: Zlib::BEST_SPEED)
# Maximum compression
small = Philiprehberger::GzipKit.compress(data, level: Zlib::BEST_COMPRESSION)
# No compression (store only)
raw = Philiprehberger::GzipKit.compress(data, level: Zlib::NO_COMPRESSION)
require "philiprehberger/gzip_kit"
result = Philiprehberger::GzipKit.compress(data, stats: true)
# => { data: "...", ratio: 0.85, original_size: 10000, compressed_size: 1500 }
require "philiprehberger/gzip_kit"
Philiprehberger::GzipKit.compressed?(gzip_data) # => true
Philiprehberger::GzipKit.compressed?("plain text") # => false
require "philiprehberger/gzip_kit"
# Compress a file
Philiprehberger::GzipKit.compress_file("data.txt", "data.txt.gz")
# Decompress a file
Philiprehberger::GzipKit.decompress_file("data.txt.gz", "data.txt")
# Compress with progress callback
Philiprehberger::GzipKit.compress_file("data.txt", "data.txt.gz") do |bytes_processed, total_bytes|
puts "#{bytes_processed}/#{total_bytes} bytes"
end
# Decompress with progress callback (total_bytes is nil)
Philiprehberger::GzipKit.decompress_file("data.txt.gz", "data.txt") do |bytes_processed, total_bytes|
puts "#{bytes_processed} bytes decompressed"
end
require "philiprehberger/gzip_kit"
# Compress from one IO to another
File.open("input.txt", "rb") do |input|
File.open("output.gz", "wb") do |output|
Philiprehberger::GzipKit.compress_stream(input, output)
end
end
# Decompress from one IO to another
File.open("output.gz", "rb") do |input|
File.open("restored.txt", "wb") do |output|
Philiprehberger::GzipKit.decompress_stream(input, output)
end
end
Streaming and file methods read in 64 KB chunks by default. Override with chunk_size: to tune for memory constraints or throughput:
require "philiprehberger/gzip_kit"
# Smaller chunks for memory-constrained environments
File.open("input.txt", "rb") do |input|
File.open("output.gz", "wb") do |output|
Philiprehberger::GzipKit.compress_stream(input, output, chunk_size: 4 * 1024)
end
end
# Larger chunks for bulk throughput
Philiprehberger::GzipKit.compress_file("input.bin", "output.gz", chunk_size: 1 * 1024 * 1024)
Philiprehberger::GzipKit.decompress_file("output.gz", "restored.bin", chunk_size: 1 * 1024 * 1024)
chunk_size: must be a positive Integer; any other value raises ArgumentError.
Mirror of compress(..., stats: true) — returns a hash with the decompressed payload and the compressed-to-decompressed size ratio:
require "philiprehberger/gzip_kit"
compressed = Philiprehberger::GzipKit.compress("a" * 10_000)
result = Philiprehberger::GzipKit.decompress(compressed, stats: true)
# => { data: "aaaa...", ratio: 0.0041 }
The ratio is compressed_size / decompressed_size (inverse of compression ratio). For zero-length output, ratio is 0.0.
require "philiprehberger/gzip_kit"
part_a = Philiprehberger::GzipKit.compress("Hello, ")
part_b = Philiprehberger::GzipKit.compress("world!")
combined = Philiprehberger::GzipKit.concat(part_a, part_b)
Philiprehberger::GzipKit.decompress(combined) # => "Hello, world!"
Compare two gzip blobs by their decompressed payload — useful when the same source is recompressed at different levels or with different metadata:
require "philiprehberger/gzip_kit"
fast = Philiprehberger::GzipKit.compress("hello", level: Zlib::BEST_SPEED)
best = Philiprehberger::GzipKit.compress("hello", level: Zlib::BEST_COMPRESSION)
Philiprehberger::GzipKit.equivalent?(fast, best) # => true
Philiprehberger::GzipKit.equivalent?(fast, Philiprehberger::GzipKit.compress("world")) # => false
require "philiprehberger/gzip_kit"
header = Philiprehberger::GzipKit.inspect_header(gzip_data)
# => { method: :deflate, mtime: 2026-03-28 12:00:00 +0000, os: 255, original_name: nil, comment: nil }
| Method | Description |
|---|---|
GzipKit.compress(string, level:, stats:) | Compress a string to gzip bytes; returns stats hash when stats: true |
GzipKit.decompress(data, stats:) | Decompress gzip bytes to a string; returns { data:, ratio: } when stats: true |
GzipKit.compressed?(data) | Check if data is gzip-compressed via magic bytes |
GzipKit.compress_file(src, dest, level:, chunk_size:, &block) | Compress a file to a gzip file with optional progress callback and chunk size |
GzipKit.decompress_file(src, dest, chunk_size:, &block) | Decompress a gzip file with optional progress callback and chunk size |
GzipKit.compress_stream(io_in, io_out, level:, chunk_size:) | Streaming compression (64 KB chunks by default) |
GzipKit.decompress_stream(io_in, io_out, chunk_size:) | Streaming decompression (64 KB chunks by default) |
GzipKit.concat(data_a, data_b) | Concatenate two gzip-compressed strings |
GzipKit.equivalent?(blob_a, blob_b) | Check whether two gzip blobs decompress to equal byte strings |
GzipKit.inspect_header(data) | Read gzip header metadata without decompressing |
bundle install
bundle exec rspec
bundle exec rubocop
If you find this project useful: