Perlに限らず、一般的にプログラムではファイルからデータを読み込み、 処理をした結果をファイルに出力します。 「繰り返し - while、for -」の ページでも簡単に紹介しましたが、ここではファイルからデータを 読み込むために必要なファイルオープンと、 ファイルをオープンし処理が終了した後に行う ファイルクローズについて説明します。
ファイルからデータを読み込むためには、まずファイルを開かなければいけません。そのためには、openという関数を使います。
「繰り返し」のページでの例を再掲し、 詳しく説明します。
#!/usr/bin/perl $inputfile="kadai5-3.txt"; open (FILE, $inputfile) or die "$!"; while (<FILE>) { print $_; } close (FILE);
(実行結果) 1995 100 1996 110 1997 120 1998 130 1999 140 2000 150 2001 160
ここから細かく見ていきます。open関数が使用されている行ですが、
となっています。ここでの注意点は、
まず、1のファイルハンドルですが、難しく考える必要はありません。 処理中にデータを読み込む際に毎回「kadai5-3.txt」と 指定するのは面倒くさいものです。それを簡略化してくれる、 kadai5-3.txt に対応する記号として FILE が設定されています。つまり、ファイルハンドルは、 今どのファイルを開いているか管理するための名前です。 データを読み込む際には、 kadai5-3.txt ではなく、 FILE を使います。ちなみに、 FILE は 別の文字列でもいいわけですが、慣習として大文字で記述するようです。 ですから、 F1 や FIN など適当な表現が可能です。
次に2のファイルオープンの失敗についてです。これは、 「条件判断 - if -」で勉強した or の構文になっています。
ここでの or は、Aが偽のときに、Bを実行する という意味です。ですので、ファイルオープンに失敗したときに、 or 以下のエラーメッセージの表示が実行されるようになっています。
ちなみに、ファイルオープンに失敗する理由としては、
ことがよくあります。ファイルオープンに失敗した場合には、まず上記の2点を確認してみてください。
最後に3の $! に入れられるメッセージについてです。 もしファイルオープンに失敗した場合、次のようなメッセージが表示されます。
このメッセージを手がかりにスクリプトを修正すればいいわけです。この dieをopenの後に記述する方法は一般的ですので、 このまま覚えましょう。
上記のスクリプトでは、<FILE>が1行読み込む という命令を表しています。読み込んだ結果、ファイルの終わりでは なかったらwhile文の中を実行します。読み込まれた1行分のデータは、 文字列として $_ というデフォルト変数に入れられます。それをprint文で表示させているわけです。
また、openの方法は、読み込み用や書き出し用など、目的に応じて使い分けないといけません。
記号 | 意味 | 用例 |
---|---|---|
< | 読み込み用(なくても可) | open (FILE, '< file.txt'); open (FILE, 'file.txt'); |
> | 書き込み用 (ファイルが存在したら上書き、存在しなければ新規作成) | open (FILE, '> file.txt'); |
>> | 追加書き込み用 | open (FILE, '>> file.txt'); |
+< | <に加えて読み書き両用 | open (FILE, '+< file.txt'); |
+> | >に加えて読み書き両用 | open (FILE, '+< file.txt'); |
+>> | >>に加えて読み書き両用 | open (FILE, '+< file.txt'); |
そして、ファイルからのデータ入力やファイルへの出力が終わり、 ファイルハンドルを使用することがなくなったら close関数を使ってクローズします。
演習7-1
下記のスクリプトでは、存在しないファイル'kadai7-100.txt'を 読み込み専用で開こうとしている。スクリプトをkadai7-1.plとして作成し、 実行結果を確認せよ。
#!/usr/bin/perl open (FILE, 'kadai7-100.txt') or die "$!"; close (FILE);
ファイルに文字や数字を出力するには、printを使用します。
print ファイルハンドル (出力データ); または print ファイルハンドル 出力データ;
このファイルハンドルを省略すると標準出力(STDOUT) に出力されます。今までのprint関数の使い方は、 このファイルハンドルを省略していたわけです。
演習7-2
演習2-2の内容をkadai7-2.txt というファイルに出力したい。下記のスクリプトをkadai7-2.plとして 保存し、catを用いて実行結果を確認せよ。
#!/usr/bin/perl $file = 'kadai7-2.txt'; open (OUT, ">$file") or die "$!"; $age = 18; print OUT "私の年齢は $age 才です。\n"; print OUT "---ケース1---\n"; print OUT "365/7\n"); print OUT "---ケース2---\n"; print OUT 365/7, "\n"; print OUT "---ケース3---\n"; print OUT 365/7 . "\n"); print OUT "---ケース4---\n"; printf OUT "%f\n", 365/7; print OUT "---ケース5---\n"; printf OUT "%5.2f\n", 365/7; print OUT "---ケース6---\n"; printf OUT "%d\n", 365/7;
(実行結果の確認) % cat kadai7-2.txt 私の年齢は 18 才です。 ---ケース1--- 365/7 ---ケース2--- 52.1428571428571---ケース3--- 52.1428571428571 ---ケース4--- 52.142857 ---ケース5--- 52.14 ---ケース6--- 52
printf関数を使用すると、出力の書式を指定できます。演習7-2でも、
とありました。%fは 「10進数の浮動小数点数を出力せよ」<という命令で、それに %5.2f と指定することで、 「小数点も含めて全体を5桁、うち小数部分を2桁で出力せよ」 となります。%fのような記号は書式変換記号 とよばれます。その他の書式変換記号は次の表を見てください。
書式変換記号 | 意味 |
---|---|
%d | 引数を10進数として出力 |
%f | 引数を10進数浮動小数点数として出力 |
%c | 引数を文字として出力 |
%s | 引数を文字列として出力 |
%o | 引数を符号なし8進数として出力 |
%x | 引数を符号なし16進数として出力 |
これまでは、ファイルへの出力を見てきましたが、 標準出力(スクリーン)に %5.2f のような桁数を指定して出力 したい場合があります。このような場合、上述したように printfを使いますが、出力先にSTDOUT という標準出力を表すファイルハンドルを指定するか、 またはファイルハンドルを省略するか、どちらかの方法で実現します。
演習7-3
演習7-2ではファイルに出力していたが、今度は標準出力に出力したい。 下記のスクリプトをkadai7-3.plとして保存し、実行結果を確認せよ。
#!/usr/bin/perl print STDOUT "---ケース4-1---\n"; printf STDOUT "%f\n", 365/7; print "---ケース4-2---\n"; printf "%f\n", 365/7; print STDOUT "---ケース5-2---\n"; printf STDOUT "%5.2f\n", 365/7; print "---ケース5-2---\n"; printf "%5.2f\n", 365/7;
open関数を使う際には、dieを併用して強制終了できることを学習しました。 Perlでは、ファイルテスト演算子を用いて、ファイルに 関する情報を得ることができます。たとえば、 ファイルやディレクトリが存在するかどうかを調べるには、 ファイルテスト演算子の -e が使われます。 また、その他のファイルテスト演算子についても学習しましょう。
演習7-4
下記のスクリプトでは、ファイルテスト演算子の -e を用いて、存在しないファイル 'kadai7-100.txt'の存在を確認している。スクリプトを kadai7-4.plとして作成し、実行結果を確認せよ。
#!/usr/bin/perl $file = 'kadai7-100.txt'; if (-e $file) { print "ファイル$fileは存在します\n"; } else { print "ファイル$fileは存在しません\n"; }
演習7-5
下記のスクリプトでは、九九の結果をファイルkadai7-5.txtに書き出し、 ファイルテスト演算子の -s を用いて、 ファイルサイズを調べている。スクリプトをkadai7-5.plとして作成し、 実行結果を確認せよ。
#!/usr/bin/perl $file = 'kadai7-5.txt'; open (FILE, ">$file") or die "$!"; foreach $count1 (1 .. 9) { foreach $count2 (1 .. 9) { printf FILE "%3d", $count1*$count2; } printf FILE "\n"; } close (FILE); $size = (-s $file); print "ファイル $file のサイズは $size byteです。\n";
(実行結果) ファイル kadai7-5.txt のサイズは 252 byteです。 (ファイル kadai7-5.txt の中身) % cat kadai7-5.txt 1 2 3 4 5 6 7 8 9 2 4 6 8 10 12 14 16 18 3 6 9 12 15 18 21 24 27 4 8 12 16 20 24 28 32 36 5 10 15 20 25 30 35 40 45 6 12 18 24 30 36 42 48 54 7 14 21 28 35 42 49 56 63 8 16 24 32 40 48 56 64 72 9 18 27 36 45 54 63 72 81
演習7-6
下記のスクリプトでは、 .pl の拡張子をもつファイルの 一覧を得て、 -M を用いて、現在から何日前に ファイルが作成されたか調べている。スクリプトを kadai7-6.plとして作成し、実行結果を確認せよ。
#!/usr/bin/perl foreach (<*.pl>) { print $_, "\n"; if (-M $_ >= 7 ) { print "このファイルは1週間以上前に作られました。\n"; } }
(実行結果例) kadai3-1.pl kadai3-2.pl このファイルは1週間以上前に作られました。 kadai3-3.pl このファイルは1週間以上前に作られました。 kadai3-4.pl このファイルは1週間以上前に作られました。 kadai3-5.pl このファイルは1週間以上前に作られました。 kadai6-1.pl kadai6-6.pl kadai7-1.pl kadai7-2.pl kadai7-3.pl kadai7-4.pl kadai7-5.pl kadai7-6.pl
これまでファイルへの出力を勉強してきましたが、 Webページ上の掲示板では、同時に同じファイルに書き込みがなされる 可能性があります。ですので、あるファイルに処理している間は 他の書き込みを排除しなくてはいけません。そこで、 flockという関数を使って、ファイルをロックします。 (正確には、flockはflockをブロックするのであり、openやflockをしない書き込みをブロックするわけではありません。)
使い方 | 意味 |
---|---|
flock (FILE, 1) | 読み込み宣言ロック(ブロックモード) |
flock (FILE, 2) | 書き込み宣言ロック(ブロックモード) |
flock (FILE, 5) | 読み込み宣言ロック(非ブロックモード) |
flock (FILE, 6) | 書き込み宣言ロック(非ブロックモード) |
flock (FILE, 8) | ロック解除 |
モード | 機能 |
---|---|
ブロックモード | 対象ファイルがロックされているとき、自分がロックできるまでプログラムを一時停止して待機する |
非ブロックモード | 対象ファイルがロックされているとき、自分がロックできるかどうかをすぐに真か偽で返す |