ファイル操作
Lesson2まではマスターしたかな?では本格的に使えそうなプログラムを作っていこう!
せっかくプログラムを書いてもその場で表示するだけじゃつまらないよね?結果をファイルに書き込んでみよう。
実行前の注意は作業フォルダの実行権限に注意してね。Winは大丈夫だと思うけれど、Linuxの人はソースが間違っていなくても書き込みが実行できないよ。
ではカウンターのプログラムを作ってみよう。だからと言って、WEBサーバーをインストールした人でも訪問カウンターみたいにWEBブラウザからアクセスしないでね。WEBブラウザで表示するには少し手直しがいるんだ。
use strict;
my $countlog = 'カウントを記録するファイルパス(絶対パス)/count.txt';
my $count = 0;
{
open(FO,"< $countlog") || open(FO,"> $countlog");
my @temp = <FO>;
close(FO);
$count = join('',@temp);
}
$count += 0;
$count++;
open(FO,"> $countlog");
print FO $count;
close(FO);
exit;
「count.txt(カウントを記録するファイル名)」には絶対パスを入力してね。相対パスは!とても危険!だ。どれくらいかと言うと危険度MAX10の内、危険度11くらい。ちなみにWinXPの場合はコマンドプロンプトを立ち上げた時に「C:\Documents and Settings\ユーザー名>」となっていると思うけど、相対パスはその場所から。test.plからのパスではないから知らないとハマるよ。なにはともあれ絶対パスが安心だ。悪いことは言わないから習慣にしておこう。
実行できたかな?普通に実行できたけれど「count.txt」が見当たらない場合、ファイル名をきちんと確認してパソコン内をくまなく検索しよう・・・そうならない為にもファイル名にはとても注意が必要だ。Winの人は特に危険だね。で、こういうときにWEBサーバー内で実行をしていると危険度が多少は軽減されるんだ。それはWEBサーバーで読み書き可能なフォルダやファイルを決めておけるからなんだ。
注意して欲しいのは、排他制御できるエディタで「count.txt」を開いているとPerlでファイル操作が上手いことできなくてカウントもできないよ。このミスはなかなか気付かずに悩みこんでしまう。kimiも初めてこのミスに出会ったときは相当悩んだよ。初心者のうちに良いことを知って得したね。
何、{}って?
いじわるなkimiは意味も無く書いてみた・・・訳ではない。「my $**」は変数だったよね。これら変数の使える範囲をスコープと言うんだけれど、スコープは宣言された{}内だけなんだ。で、こういった限られた範囲内でしか使えない変数を局所変数とかローカル変数という。その反対はどこでも使える大域変数とかグローバル変数と言う。ちなみに大体皆英語バージョンの呼び方を使っているよ。
「でも変数がないじゃん、やっぱり意地悪かっ!」って?「my @**」があるじゃないか・・・まぁ、説明は少しまってね。
open(FO,"< $countlog")?
open関数で「count.txt」をオープンしてFOと名付けたファイルハンドルに対応させた。詳しくはopenへ。ファイルハンドルとは、Perlがパソコンの入出力(主にファイルとの)とやり取りする時に使う名前みたいなもの。Perl君が「俺はこれからcount.txtのある場所をFOと呼ぶ」って決めたと考えればいいと思うよ。命名方法は変数と同じだけれど大文字を使う習慣があるんだ。だからって$はいらないよ。
「||」???
「||」は演算子(後のLessonで説明)の仲間で「左辺もしくは右辺」って意味。だから左辺の結果が「よくできました」なら右辺は評価されない。左辺の結果が「がんばりましょう」なら次に期待して右辺を評価するんだ。ついで?にプログラムの世界では「よくできました」を「真」、「がんばりましょう」を「偽」ということを覚えてね。ちなみに「||」は「or」で書き直してもきちんと動くよ。
このプログラムでは「open(FO,"< $countlog")」のがんばりを評価する為に存在する。
え、「||」が書けない?キーボードのShift+¥が2本だよ。
open(FO,"> $countlog")?
左辺ががんばってファイルを読み込みモードで開こうとしたけれど、ファイルが無くて失敗したときに、書き込みモードでファイルを作ってあげるために居る。
だから二回目からのプログラムの実行で、すでに「count.txt」があると評価(実行)されない。
my @temp = <FO>;
「$」じゃないの?そう、ここは「@」が望ましい。「@」は配列といって変数のグループみたいなものなんだ。一つ一つを要素といって、一つ目の要素は「$temp[0]」で「$temp[1]」は二つ目だから注意してね。これら要素は変数と同じようにつかえるよ。「空」の配列は「@temp=();」と宣言するんだ。いっぱい宣言する時は「,」で区切って「my @temp=('a',123,'b','cde','f',...);」としたらいいよ。このとき$temp[2]は'b'だね。
望ましいというのは「= <FO>」の部分に関係があるんだ。細かく言えば「=」は<FO>から一行ずつ代入すること。だから相手が「$」で単品の変数だと最初の一行しか入らない。「@」で配列を宣言しておけば「$temp[0]」から順番に<FO>の最後まで一行ずつ勝手に入れてくれるんだ。カウンターなんて一行だろうけど、ファイルハンドルはなるべく配列にいれようね。
で、「@temp」はココと次の次の行しか使わない。だから邪魔にならないように「{}」を使ってローカル変数にしているんだ。この例は極端だけれど、ローカル変数で済むものはローカル用で宣言するのがややこしいプログラムにならないためのコツだね。それよりも、グローバル変数を極力減らすという言い方の方が合っているかな。
$count = join('',@temp);
@tempを一つの文字列にして変数に代入できるようにしているんだ。詳しくはjoinへ。これといって難しいことはしていないけれど、「$count」は「0」を代入して数字の変数になっているのは覚えているかな?今ココで「$count」は文字列の変数になったんだ。
Perl言語しか知らないとこれが普通になってしまうかもしれないけれど、C言語等は数字や文字、その他もろもろを代入できる変数がそれぞれ違う。プログラマーとして頭の片隅に入れておいてね。
$count += 0;
「zero足してどおするの?」だって?これはね、ちょっと荒業で、再び「$count」を数字に戻しているんだ。実行する時に警告が出てちょっと起こられるかもしれないけれど、一番てっとり早い。「0」を足すことで数字の変数だと判断してくれて、先頭から数字以外の文字までを数字にしてくれるんだ。ちなみに「$count += '0';」だと違う意味だから気をつけてね。他の方法は「理解が」少しめんどくさいから、特に気にすることがなければ今はこれで良いと思う。
ま、このプログラム用途ならこの行自体がなくても動くけど「困った時の予備知識」だと思ってね。
$count++;
変数の横の「++」は演算子の仲間。インクリメントといって一つ足すという意味だ。便利だから良くつかう。代入されているモノによって何が足されるかはその時々で違うから(厳密に言うと内部の処理は一緒だけど・・・)、説明を読んだりするよりもイロイロ試してみると面白いと思うよ。ココでは数字だから予想通りの「1」が足される。
もちろん反対もあって、「--」が一つ引くと言う演算子。その名もデクリメントさ。
print FO $count;
「FO」がなければコマンドプロンプトだったね。ファイルハンドルを指定するとそこに表示するんだ。「え、見えない?」だって?そ、まだ見えない。
テキストエディタで普通に文章を書いていても上書きしないで閉じると前のままだよね?同じように、printでどんだけ表示しようが書き込まないと無駄になってしまうよ。
テキストエディタ作業の言葉を使うと、前の行のopenで「count.txt」をクリアして開き、printで編集して、次の行のcloseで書き込みって感じかな。ただ、closeがなくてもプログラムが終われば勝手に閉じるんだ。でも開けたらちゃんと閉める。
ということで?開けたらなるべく早く閉めるプログラムを心がければ停電しても被害を少なくできるよ。
これくらいのプログラムなら、読み書き用でオープンして一連の動作が終わってからクローズするようなプログラムでもいいね。
Lesson3を終わるね。そろそろ簡単なものなら作れるようになっているんじゃないかな?例と同じ結果を出すプログラムを色んな方法で書いてみてはいかがかな?例えばさっきも言ったオープンとクローズを一回ずつしか使わない方法で書いてみたりね。注意点は、「@temp」に代入した時、FOのファイルポジション(エディタで言うカーソル)が最後に行ってしまっているから、そのときはseekを使うといいよ。Lesson4へ行く前の課題ね。