その手の平は尻もつかめるさ

ギジュツ的な事をメーンで書く予定です

ファイルハンドルに対するbinmodeの変更が及ぼす影響を小さくしたい

ファイルハンドルをbinmodeで変更して,そのファイルハンドルを用いて何らかの処理を行いたい,という欲求がしばしばあると思います.
単純に書くと以下のようになるでしょう.

このコードではファイルハンドルを普通にopenして,それをawesome_function()に渡して,そのawesome_function()内でbinmode $fh, ':encoding(utf-8)'を使ってファイルハンドルのencodingを変更して,そのファイルハンドルで何らかの処理を行っています.
ぱっと見これで良い感じがしますが,このコードには問題があって,awesome_function()内でのファイルハンドル$fhの変更は他の箇所,つまりawesome_function()の外にも影響を及ぼします.
上のコードを例に取ると,awesome_function()を呼ぶ前のファイルハンドル$fhはencodingが変更されていませんが,呼び出した後のファイルハンドル$fhはencodingが変更されています.これだと具合が悪い時がままある.


こうした場合に,ファイルハンドルへの変更をawesome_function()内で留めたい場合どうすれば良いのかと考えた時に,とりあえずファイルハンドルを複製して,その複製したファイルハンドルに対して変更を与えてからそれを使って処理すれば良いのではないか,という感じになりました.こんな感じ.

awesome_function()内でファイルハンドルを複製して *1,その複製したファイルハンドル$fh_copyに対してbinmodeでencodingを変更してやってから$fh_copyを使って処理を行なってやれば,元のファイルハンドルに変更を及ぼすことが無くなります.つまり,awesome_function()を呼んだ後であっても元のファイルハンドルは変更されません.


こうした場合はファイルハンドルの複製でなんとかなるんじゃないかと思った次第です.なんか駄目そうだったら教えて下さい.


なおファイルハンドルの詳細な情報 (layer) はPerlIOの関数であるget_layers()に対してdetailsフラグを立てて実行すると参照することが出来ます.上記コードだと以下の様な出力が得られます.

$VAR1 = 'unix';
$VAR2 = undef;
$VAR3 = 2098176;
$VAR4 = 'perlio';
$VAR5 = undef;
$VAR6 = 4195328;
$VAR7 = 'encoding';
$VAR8 = 'utf-8-strict';
$VAR9 = 4228096;

この結果から,encodingがutf-8-strictであることがわかりますね.

ちなみにdetailsを使ったPerlIO::get_layersにのドキュメントには“Implementation details follow, please close your eyes.”とか書いてあって大変クール!


CLOSE YOUR EYES/YAMATO-男たちの大和 主題歌-

CLOSE YOUR EYES/YAMATO-男たちの大和 主題歌-

*1:ファイルハンドルの複製についてはopen()を参照して下さい http://perldoc.perl.org/functions/open.html