続・はじめてのPerl 8章
今日も(ry
8.1 古い方法
ファイルハンドルはデータ型の1つ ライブラリや、コードの他の部分で共有するには? 型グロブや型グロブリファレンスを使う 型グロブ 名前のすべてのパッケージ変数を指すポインタを格納している 型グロブを別の型グロブに代入することで、同じデータの別名を作ることができる 名前をファイルハンドルとして扱うとき、Perlは型グロブのファイルハンドル部を探す 型グロブはシンボルテーブルを操作する つまり、パッケージ変数を処理する
open LOG_FH, ">> log.txt" or die $!; log_message( *LOG_FH, 'log message' ); close LOG_FH; sub log_message { local *FH = shift; print FH @_, "\n"; }
上記のコードで、localを使う理由 パッケージ変数はレキシカル変数になれないので、FHをmyで宣言することはできない localを付けないFHに代入した場合 スクリプト内のどこかで、FHという名前が付けられているものを壊してしまう localを付けるたFHに代入した場合 log_messageサブルーチンの実行中、FHという名前には一時的な値が格納される サブルーチンから制御が戻るときに、PerlはFHを元の値に戻す これらのやり方は「古い方法」
8.2 改良された方法
openで、ファイルハンドルリファレンスを作れるように Perl5.6以降から ファイルハンドルに指定できるのは、値がundefのスカラー変数 スカラー変数がundefでなかった場合 strictプラグマを使用しているとエラーとなり動作しない ファイルハンドルに指定する変数は、openの中で宣言可能 飾りなしのファイルハンドルを使っていた箇所で、 スカラー変数のファイルハンドルリファレンスを使える スカラー変数のファイルハンドルリファレンスは、 スコープから外れる、または、他の値が代入されるとファイルをクローズする 明示的にクローズする必要はない
# openの中で変数の宣言 open my $log_fh, ">> log.txt" or die $!; log_message( $log_fh, "log message"); sub log_message { my $fh = shift; # 出力 print $fh @_, "\n"; }
8.3 さらによい方法
3引数形式のopenを使う 2引数形式では、第2引数で指定した文字列をPerlが正しく解釈しない可能性がある
# 3引数形式のopen open my $log_fh, '>>', 'log.txt' or die $!;
8.4 IO::Handle
IO::Handle 入出力全般の基底クラス ファイルだけではなく、多くのものを処理する Perlは、裏でIO::Handleモジュールを使用している ファイルハンドルスカラーは、実際はオブジェクト 新しいIOモジュールを作ること以外で、IO::Handleは直接使わないようにするべき IO::Handleの派生モジュールを使用するべき Perl組み込みのopenですでにできることも含まれている できることは、Perlのバージョンで異なる 組み込み関数でできることを、モジュールインターフェイスで利用する理由 どのモジュールを使い入出力を行うのか先延ばしできる モジュール名を変更するだけで、動作の切り替えができる
8.4.1 IO::File
IO::File IO::Handleの派生クラス ファイルを操作する Perlのコアモジュール
use IO::File; # 1引数形式のコンストラクタ my $fh = IO::File->new( '> log.txt' ) || die $!; # 2引数形式のコンストラクタ # 第2引数はファイルハンドルのアクセスモード # ANSI Cのfopenのモード文字列 # モード文字列は組み込みのopenでも使える my $read_fh = IO::File->new( 'log.txt', 'r' ); my $write_fh= IO::File->new( 'log.txt', 'w' ); # アクセスモード引数にビットマスクを使うことで、より細かく動作をコントロール可能 # 定数は、IO::Fileモジュールが提供 my $append_fh = IO::File->new( 'log.txt', O_WRONLY|O_APPEND ); # 一時ファイルの作成 # 読み書き用のファイルハンドルを取得できる my $temp_fh = IO::File->new_tmpfile; # 明示的にクローズ $temp_fh->close; undef $append_fh; # 明示的にクローズしない場合、 # ファイルハンドルは、スコープから外れるとクローズされる
8.4.2 無名IO::Fileオブジェクト
IO::Fileオブジェクトは、スカラー変数以外にも代入可能 配列の要素 ハッシュの値
8.4.3 IO::Scalar
IO::Scalar スカラーに情報を追加できるファイルハンドルリファレンスを作成する Perlのコアモジュールではない
use IO::Scalar; my $string_log = ''; my $scalar_fh = IO::Scalar->new( \$string_log ); # メッセージは、$string_logに格納される print $scalar_fh "Hello, IO::Scalar!\n"; print $scalar_fh "Hello, IO::Scalar!!\n"; print $scalar_fh "Hello, IO::Scalar!!!\n"; $scalar_fh = IO::Scalar->new( \$string_log ); while ( <$scalar_fh> ) { print; }
# Perl5.8以降では、IO::Scalarを使わずに同じことが可能 my $string_log = (); open( my $fh, '>>', \$string_log ) || die $!; print $fh "not use IO::Scalar!\n"; print $fh "not use IO::Scalar!!\n"; print $fh "not use IO::Scalar!!!\n"; print $fh "not use IO::Scalar!!!!\n"; open( $fh, '<', \$string_log ) || die $!; while ( <$fh> ) { print; }
8.4.4 IO::Tee
IO::Tee 出力を多重化できる 第1引数が入力ファイルハンドルの場合 Teeファイルハンドルを使い、入力ファイルからの読み出しと出力ファイルへの書き込みの両方が可能 第1引数以外は、出力ファイルハンドルである必要がある
use IO::File; use IO::Scalar; use IO::Tee; # 出力の多重化 { my $log_fh1 = IO::File->new( 'log1.txt', 'w' ); my $log_fh2 = IO::File->new( 'log2.txt', 'w' ); my $tee_fh = IO::Tee->new( $log_fh1, $log_fh2 ); print $tee_fh "output tee_fh!\n"; } # 第一引数が入力ファイルハンドル { my $read_fh = IO::File->new( 'log.txt', 'r' ); my $log_fh1 = IO::File->new( 'log1.txt', 'w' ); my $log_fh2 = IO::File->new( 'log2.txt', 'w' ); my $tee_fh = IO::Tee->new( $read_fh, $log_fh1, $log_fh2 ); while ( <$tee_fh> ) {}; print $tee_fh "end\n"; }
8.5 ディレクトリハンドルリファレンス
# ファイルハンドルリファレンスと同様に、 # ディレクトリハンドルリファレンスの作成も可能 opendir my $dh, '.' or die $!; for my $file ( readdir( $dh ) ){ print $file, "\n"; }
感想
IO::Teeの第一引数が入力ファイルハンドルのものが、動作が想像してたものと違った。
本のニュアンスでは、明示的に書き込まないと書き込まれないように受け取れたが、
実際サンプルコードを動かすと、読み込むと同時に書き込みが行われているようだ。
あとでちゃんと調べよう。
- 作者: Randal L. Schwartz,brian d foy,Tom Phoenix,吉川英興,伊藤直也,田中慎司,株式会社ロングテール/長尾高弘
- 出版社/メーカー: オライリー・ジャパン
- 発売日: 2006/10/21
- メディア: 大型本
- 購入: 9人 クリック: 389回
- この商品を含むブログ (99件) を見る