複数のGzipデータを連結した1つのデータ
gzipコマンドは複数のgzip圧縮されたファイルをcatで結合したものでも展開することができます。簡単な例をbashで見てみましょう
date --iso-8601=ns | gzip > a.gz
date --iso-8601=ns | gzip > b.gz
cat a.gz b.gz > all.gz
gzip -dc all.gz # 2行出てくる
RFC1952でファイルフォーマットについて説明があります。
Gzipファイルフォーマットは先頭10byteは必ずメンバ情報になっており、あとはメンバ情報のFLGによって可変長データが続くような形になっています。
この繰り返しなので、複数の圧縮されたデータがあっても、ひたすら展開して連結することで1つのデータが得られる仕組みになっているようです。上記の通り、gzipコマンドやzcatコマンドや著名なアーカイバ(7-zipとか)はサポートしています。
RubyのZlib::GzipReaderはサポートしているか?
2021/10/05時点の実装ではZlib::GzipReader.zcat
でサポートしているようですが、RubyGemsで公開されているバージョン(1.1.0)ではまだ入っていないようで、まだサポートされていない、といえる状態です。
- Issue: https://github.com/ruby/zlib/issues/7
- 実装箇所: https://github.com/ruby/zlib/blob/master/ext/zlib/zlib.c#L3861
- RubyGems: https://rubygems.org/gems/zlib/versions/1.1.0
なので、適当に処理するしかないので、こんな感じにします。Rubyは全く書かないので、この実装で良いかは怪しいです。
def uncompress(gzip_data)
decoded_data = ""
while gzip_data do
Zlib::GzipReader.wrap(StringIO.new(gzip_data.b)) do |gz|
decoded_data << gz.read
gzip_data = gz.unused
end
end
decoded_data
end
readで1つ分は読めて、unusedに余ったデータが残るので、残ったデータに対してまたreadを繰り返して連結していきます。
雑過ぎますが、テストコードで必要になった実装なので雑でいいんです(いいのか?)
zcatが待ち遠しいですね。