行入力演算子「<>」 - ファイルから一行読み込む
ファイルを一行づつ読み込むには行入力演算子「<>」を使用します。読み込む行がなくなると、undefを返却します。
my $line = <$fh>;
他の演算子と異なり「<」と「>」の間にファイルハンドルを記述することに注意してください。
通常は、while文と組み合わせて、繰り返して行を読み込むのに利用します。
while(my $line = <$fh>) { # ... }
考え深い方は、上記のように書いた場合は、もし「0」などの偽の値が返ってきた場合は、正しく動かないんじゃないかと感じるのではないでしょうか。行の途中は、改行コードが入りますから、「0」が返ることはありませんが、末尾の場合は「0」が返ってくる可能性があります。
でも、心配しないでください。ファイル演算子は、whileと組み合わされて使う場合のみ、次のように解釈されるからです。
while(defined(my $line = <$fh>)) { # ... }
ですから、whileと組み合わせて使っている限りは、最初の書き方で問題ありません。
ダイヤモンド演算子
行入力演算子で「<」と「>」の間に何もない「<>」という記述の場合は、特別にダイヤモンド演算子と呼ばれます。ファイルハンドルが省略された場合は、標準入力と、コマンドライン引数で指定されたファイル名から、1行づつ読み込むことができます。
# ダイヤモンド演算子 my $line = <>;
ダイヤモンド演算子を使用すればファイルから1行読み込みを簡単に行うことができます。標準入力とコマンドライン引数で与えられたファイルから一行ずつ順に読み込みます。
while (my $line = <>) { ... }
ダイヤモンド演算子を使う利点は「標準入力から他のプログラムの出力を受け取ることができるプログラム」を簡単に書けるということです。これは一般的なUNIXユーティリティであるcat,sed,awk,grepなどと同じ動きです。
# コマンドライン引数からファイル名を受け取る script.pl file.txt # 他のプログラムの出力をパイプを使って標準入力から受け取る grep hello file.txt | script.pl
もう一つの利点はわざわざopenやcloseをする必要がないということです。短いプログラムではダイヤモンド演算子を利用すると簡単にプログラムを書くことができるので便利です。
受け取った行をそのまま出力するサンプルです。
# 受け取った行をそのまま出力する use strict; use warnings; while (my $line = <>) { print $line; }
配列に一度に取り込む
行入力演算子を、リストコンテキストで評価すると、すべての行を配列に取り込むことができます。けれども、ファイルが大きい場合は、メモリの使用量が大きくなるので、注意してください。
my @lines = <$fh>
ファイルのすべての内容を取り込む
ファイルのすべての内容を取り込むには、次のような書き方が一般的です。
my $content = do { local $/; <$fh> };
「$/」は、行の区切り文字です。これを未定義にすれば、行入力演算子は、ファイルの内容をすべてを取り込みます。localを使って、一時的に未定義にしています。doブロックは、最後に評価された値を返します。ですから、この記述で、ファイルの内容を一度に読み込むことができます。
サンプル
行入力演算子を使って、ファイルを1行ずつ読み込むサンプルです。1行読みこみを while ループで繰り返します。
use strict; use warnings; # ファイルリード # readline $fh # <$fh> # 読み込みたいファイル名 my $file = shift; open(my $fh, "<", $file) or die "Cannot open $file: $!"; print "1: ファイルリードの一般的な記述\n"; # readline関数で、一行読み込む。 while(my $line = readline $fh){ # chomp関数で、改行を取り除く chomp $line; # $line に対して何らかの処理。 # 標準出力へ書き出し。 print $line, "\n"; # ファイルがEOF( END OF FILE ) に到達するまで1行読みこみを繰り返す。 } close $fh;
コード解説
(1)1行ファイル読み込み
while (my $line = readline $fh) { # 処理 ... }
ファイルを1行づつ読み込むには、readline関数を使用します。$fhは、open関数でオープンしたファイルハンドルです。1行読み込みをwhile文で繰り返して、ファイルの最後まで読み込んでいきます。
whileループの条件文を書く位置で、1行読みこみを行っているのは変に感じるかもしれませんがこのような記述が可能です。my $line = readline $fh という記述で、$lineというレキシカル変数を宣言して、$line に、読み込んだ1行を代入しています。$line は、whileループの中でだけ有効で、外からは見えません。
ファイルの終わりに到達すれば、readline関数はundefを返し、$lineにundefが代入されます。$lineがundefなので、while文は終了します。
(2)chomp関数で改行を取り除く
while (my $line = readline $fh) { chomp $line; # 処理 ... }
行を読み込んだら改行が不必要な場合が多いので、chomp関数を使って改行を取り除きます。
(3)readlineのもうひとつの書き方 <$fh>
while (my $line = <$fh>) { # 処理 ... }
Perlでは、 < > の中にファイルハンドルを入れると、readline $fh と同じ意味になります。簡便な記述を好む場合はこちらを使います。