Simple zcat(1) in Perl with Compress::Raw::Zlib
Perlのzlibインターフェイスは沢山あってよく分からないが、単純に圧縮/解凍をするだけならCompress::Raw::Zlibがシンプルで良さそうだ。
これでzcat(1)を実装すると以下のようになる。
#!perl -w use strict; use Compress::Raw::Zlib; my $z = Compress::Raw::Zlib::Inflate->new( -WindowBits => WANT_GZIP, ); foreach my $file(@ARGV) { open my $fh, '<', $file or die "Cannot open $file: $!"; while(read $fh, my $buf, 1024) { my $d; my $status = $z->inflate($buf, \$d, 1); ($status == Z_OK or $status == Z_STREAM_END) or die "Inflation error: $status"; print $d; } }
その他のハイレベルなライブラリ、たとえばIO::ZlibやIO::Compress::Gzip/IO::Uncompres::Gunzipなどは、圧縮アルゴリズムに関わらない統一したインターフェイスを提供するなどの利点があるが、対象がgzip固定ならC::Raw::Zlibで何の問題もなく、むしろ軽くて使いやすい。
また、上記のハイレベルなライブラリはコンストラクタでgzip headerの妥当性をチェックする等ある意味エラーに強いのだが、ソケットのように一度のreadで完全なgzip headerを読み込めない可能性があるファイルハンドルを渡すとデータが不整合とみなされる事があり、HTTP clientには適さない。この点、C::Raw::Zlibのinflate()は1 byteずつ渡しても正しく処理してくれるため、HTTP clientでは積極的に採用する理由がある。