perlopentut - Perl でファイルを開いたりパイプを使ったりするための簡単なレシピ
Perl でファイルにタイして入出力をするとき、Perl では ファイルハンドル と 呼ばれるものを通して行います。 ファイルハンドルは外部ファイルに対する内部名です。 open
関数の仕事は内部名と外部名を関連づけることで、close
関数は 関連づけを壊すことです。
便利なように、Perl は実行開始時に既に開いているいくつかの特別な ファイルハンドルを設定します。 それは STDIN
, STDOUT
, STDERR
, ARGV
です。 これらは既に開いているので、自分でこれらを開くときの問題を受けることなく 正しく使うことができます。
print STDERR "This is a debugging message.\n";
print STDOUT "Please enter something: ";
$response = <STDIN> // die "how come no input?";
print STDOUT "Thank you!\n";
while (<ARGV>) { ... }
これらの例で見られるように、STDOUT
と STDERR
は出力ハンドルで、 STDIN
と ARGV
は入力ハンドルです。 これらは @ARGV
配列や %ENV
ハッシュと同様に Perl によって 予約されているので、全て大文字になっています。 これらの外部関連づけはシェルによって行われます。
その他のファイルハンドルは自分で開く必要があります。 多くのバリエーションはありますが、Perl の open() 関数を開く最も一般的な方法は 3 引数と一つの返り値のものです:
OK = open(HANDLE, MODE, PATHNAME)
ここで:
これは、開くのに成功すれば何らかの定義された値、失敗すれば undef
です;
これは、成功すれば open
巻数によって埋められる未定義のスカラ変数です;
これはファイルを開くときのアクセスモードとエンコーディング型式です;
これは開きたいファイルの外部名です。
open
関数の複雑さの大部分は、MODE 引数が多くの値を 取ることのできることにあります。
ファイルの開き方を説明する前に最後に一言: Perl ではファイルを開いても (普通は)自動的にロックすることはしません。 ロックの方法については perlfaq5 を参照してください。
テキストファイルを読み込みたい場合、まず次のように読み込み専用モードで 開きます:
my $filename = "/some/path/to/a/textfile/goes/here";
my $encoding = ":encoding(UTF-8)";
my $handle = undef; # this will be filled in on success
open($handle, "< $encoding", $filename)
|| die "$0: can't open $filename for reading: $!";
シェルと同様に、Perl でもファイルを読み込み専用モードで開くために "<"
が使われます。 これに成功すると、Perl は新しいファイルアンドルを割り当て、未定義だった $handle
引数にそのハンドルへのリファレンスを設定します。
これでこのハンドルに対して readline
, read
, getc
, sysread
のような関数が使えます。 おそらく最も一般的な入力関数は演算子のように見えるものでしょう:
$line = readline($handle);
$line = <$handle>; # same thing
readline
関数はファイル終端やエラーのときに undef
を返すので、 時々次のように使われているのを見るでしょう:
$line = <$handle>;
if (defined $line) {
# do something with $line
}
else {
# $line is not valid, so skip it
}
また、次のようにして単に未定義値に対してすばやく die
することもできます:
$line = <$handle> // die "no input found";
しかし、EOF に到達するのが想定されていて通常の出来事の場合は、 入力がなくなっただけで終了したくありません。 そうではなく、単に入力ループを終了したいでしょう。 実際のエラーがループを終了させたのかをテストして、適切に行動できます:
while (<$handle>) {
# do something with data in $_
}
if ($!) {
die "unexpected error while reading from $filename: $!";
}
エンコーディングに関する注意: テキストエンコーディングを毎回指定する 必要があるのは少し面倒に感じるかもしれません。 毎回設定する必要がないように open
のためのデフォルトエンコーディングを 設定するために、open
プラグマを使えます:
use open qw< :encoding(UTF-8) >;
一度これを行えば、open モードからエンコーディングの部分を安全に省略できます:
open($handle, "<", $filename)
|| die "$0: can't open $filename for reading: $!";
しかし、先にデフォルトのエンコーディングを設定することなく裸の "<"
を使うことは決してしないでください。 さもなければ、Perl はとてもとてもとてもたくさんあるテキストファイルの 種類のうちどれかを知ることができず、Perl はあなたのファイルのデータを 動作させるための実際の文字にマッピングすることができません。 その他のよくあるエンコーディング形式には "ASCII"
, "ISO-8859-1"
, "ISO-8859-15"
, "Windows-1252"
, "MacRoman"
および、 "UTF-16LE"
すらもあります。 エンコーディングに関するさらなる情報については perlunitut を 参照してください。
ファイルに書き込みたい場合、そのファイルの既存の内容をどうするかを まず決定する必要があります。 二つの基本的な選択肢があります: 保存するか上書きするかです。
既存の内容を保存したい場合、ファイルを追記モードで開きます。 シェルと同様に、 Perl でも既存のファイルを追記モードで開くために ">>"
が使われます。 ファイルがない場合、">>"
はファイルを作ります。
my $handle = undef;
my $filename = "/some/path/to/a/textfile/goes/here";
my $encoding = ":encoding(UTF-8)";
open($handle, ">> $encoding", $filename)
|| die "$0: can't open $filename for appending: $!";
これでこのハンドルに対して print
, printf
, say
, write
, syswrite
を使って書き込めます。
前述したように、ファイルが既に存在していない場合、追記モードで開くと ファイルを作ります。 しかしファイルが既に存在している場合、その内容は保護されます; 新しいテキストは 既存のテキストの末尾に追加されるからです。
一方、時々、既に何かがあっても上書きしたいときもあります。 書き込みを始める前にファイルを消すために、書き込み専用モードで 開くことができます:
my $handle = undef;
my $filename = "/some/path/to/a/textfile/goes/here";
my $encoding = ":encoding(UTF-8)";
open($handle, "> $encoding", $filename)
|| die "$0: can't open $filename in write-open mode: $!";
ここで再び Perl はシェルと同様に動作し、">"
は既存のファイルを 上書きします。
追記モードと同様に、ファイルを書き込みモードで開くと、 print
, printf
, say
, write
, syswrite
を使って ファイルハンドルに書き込めるようになります。
読み書きモードについては? おそらくそれは存在しないというふりをした方がよいでしょう; なぜならテキストファイルを読み書きモードで開いても おそらくあなたが望んでいることをしないからです。 詳しくは perlfaq5 を参照してください。
開こうとしているファイルがテキスト文字ではなくバイナリデータが含まれている 場合、open
の MODE
引数は少し異なるものになります。 エンコーディングを指定する代わりに、データが生のバイト列であることを Perl に知らせます。
my $filename = "/some/path/to/a/binary/file/goes/here";
my $encoding = ":raw :bytes"
my $handle = undef; # this will be filled in on success
それから前述の通り、必要に応じて "<"
, ">>"
, ">"
を選びます:
open($handle, "< $encoding", $filename)
|| die "$0: can't open $filename for reading: $!";
open($handle, ">> $encoding", $filename)
|| die "$0: can't open $filename for appending: $!";
open($handle, "> $encoding", $filename)
|| die "$0: can't open $filename in write-open mode: $!";
あるいは、次のようにして既に存在しているハンドルをバイナリモードに 変えることが出来ます:
binmode($handle) || die "cannot binmode handle";
これは、Perl が既に開いているハンドルに対して特に有用です。
binmode(STDIN) || die "cannot binmode STDIN";
binmode(STDOUT) || die "cannot binmode STDOUT";
また、その場で変更するために binmode
に明示的にエンコーディングを 渡すこともできます。 これは正確には「バイナリ」モードではありませんが、それでも これをするために binmode
を使います:
binmode(STDIN, ":encoding(MacRoman)") || die "cannot binmode STDIN";
binmode(STDOUT, ":encoding(UTF-8)") || die "cannot binmode STDOUT";
一旦バイナリファイルを正しいモードで適切に開くと、テキストファイルで 使ったものと全て同じ Perl I/O 関数を使えます。 しかし、入力に対して可変長の readline
ではなく固定長の read
を使った方が良いでしょう。
次のものはバイナリファイルをコピーする例です:
my $BUFSIZ = 64 * (2 ** 10);
my $name_in = "/some/input/file";
my $name_out = "/some/output/flie";
my($in_fh, $out_fh, $buffer);
open($in_fh, "<", $name_in)
|| die "$0: cannot open $name_in for reading: $!";
open($out_fh, ">", $name_out)
|| die "$0: cannot open $name_out for writing: $!";
for my $fh ($in_fh, $out_fh) {
binmode($fh) || die "binmode failed";
}
while (read($in_fh, $buffer, $BUFSIZ)) {
unless (print $out_fh $buffer) {
die "couldn't write to $name_out: $!";
}
}
close($in_fh) || die "couldn't close $name_in: $!";
close($out_fh) || die "couldn't close $name_out: $!";
未定。
未定。 または削除する。
未定。
Copyright 2013 Tom Christiansen.
This documentation is free; you can redistribute it and/or modify it under the same terms as Perl itself.