┌──────────────────┐
│Perl小技 : gzipファイルのRead/Write │
└──────────────────┘


[▲Perl Home▲]

●gzipファイルを処理する小技

 ・Perlはテキストファイルの処理を得意とする言語であることは説明するまでもありませんが、
  ターゲットとなるテキストファイルは圧縮されていることがあります。

 ・今回はLinux系でよく使用される「gzip」を例にして話をしたいと思います。

 ・Linux系は普通にインストールすれば入っていると思いますが、Windowsでgzipを利用
  したければ、下記よりダウンロード下さい。
   http://gnuwin32.sourceforge.net/packages/gzip.htm

 ・gzipの簡単な使い方ですが
   + 圧縮 : gzip 圧縮対象ファイル // gzip hoge.txt
      ===> hoge.txt.gz ができます
   + 展開 : gzip -d 圧縮ファイル // gzip -d hoge.txt.gz
      ===> hoge.txt ができます

 ・さらにRead/WriteでSTDIN/STDOUTを経由する場合は「c」オプションを追加します。
   + 展開結果をSTDOUTへ
     gzip -dc hoge.txt.gz // STDOUTへ
     → ファイル化時はリダイレクト
        gzip -dc hoge.txt.gz > hoge.txt
   + 圧縮結果をSTDOUTへ
     gzip -c hoge.txt // STDOUTへ
     → ファイル化時はリダイレクト
        gzip -c hoge.txt > hoge.txt.gz

 ・一般的にSTDIN/STDOUTが使えると、コマンド間のデータ受け渡しは、パイプ '|' を利用するこ
  とが可能になります。

   + 何かのコマンド標準出力を圧縮
    コマンド | gzip -c > リダイレクト出力
    コマンド | gzip -c | 更に他のコマンドへ
   + 何かのコマンド標準出力を展開
    コマンド | gzip -dc > リダイレクト出力
    コマンド | gzip -dc | 更に他のコマンドへ

 ・最後に説明した「パイプ」を利用して、gzipファイルをPerlから簡単に読み書きする方法を紹
  介します。


 ・下記がサンプルコードです。ファイル名の末尾を見て「.gz」の有無によりgzipを経由するかど
  うか決めています。とは言っても見るところは青字の2行だけです。

  ┌──────────────────────────────────────┐
   #!perl -w
   use FileHandle;
   use Getopt::Long;
   use strict;
   
   {
     # 引数処理
     my $opt_in = '_NULL_';  # -in 入力ファイル
     my $opt_out = '_NULL_';  # -out 出力ファイル
   
     # コマンドラインオプション取り込み
     GetOptions('in=s' => \$opt_in, 'out=s' => \$opt_out);
   
    #=======================================================================
    # ファイルOpen
    #-----------------------------------------------------------------------
     # ファイルハンドルの定義
     my $fhi;
     # ファイルOpenエラー時のメッセージ定義
     my $err_fopen = "ERROR:can not open $opt_in\n"
     
     # ファイル名判別
     if ($opt_in =~ /\.gz$/) {
       # 末尾が「.gz」ならば、gzipの標準出力をパイプ経由Open
       $fhi = FileHandle->new("gzip -dc $opt_in |") or die $err_fopen;
     } else {
       # 通常のテキストファイルとしてそのままOpen
       $fhi = FileHandle->new("< $opt_in") or die $err_fopen;
     }
     # データをリストに取り込む
     my @src = <$fhi>;
     # クローズ
     $fhi->close();
    #=======================================================================
   
     for (my $i=0; $i<@src; $i++) {
       $src[$i] =~ s/ /_/g;  # 適当な処理(意味は無い)
     }
   
    #=======================================================================
    # ファイルWrite
    #-----------------------------------------------------------------------
     # ファイルハンドルの定義
     my $fho;
     # ファイルWriteエラー時のメッセージ定義
     my $err_fwrite = "ERROR:can not write $opt_out\n"
     
     # ファイル名判別
     if ($opt_out =~ /\.gz$/) {
       # 末尾が「.gz」ならば、gzipの標準出力を経由してWrite
       $fho = FileHandle->new("| gzip -c > $opt_out") or die $err_fwrite;
     } else {
       # 通常のテキストファイルとしてそのままWrite
       $fho = FileHandle->new("> $opt_out") or die $err_fwrite;
     }
     # データをWriteする
     print $fho @src;
     # クローズ
     $fho->close();
    #=======================================================================
   }
  └──────────────────────────────────────┘

 ・サンプルコードでは、FileのOpenに FileHandle を使用していますが、当然 open 関数でも同
  様になります。

 ・Monpeはファイルハンドルを「オブジェクト」として扱いたいと考えるタイプなので、型グロブ
  を必要とするopenよりも、オブジェクトタイプのモジュールを使用しています。


[▲Perl Home▲]

2010/05/23 : 誤字修正
2010/05/05 : 初版