ファイル入出力

ファイル入出力

ファイル入出力について

ファイルからデータを読み込んだり、ファイルにデータを書き込んだりする方法です。アクセスカウンタで訪問者数を記録したり、掲示板で投稿内容を記録したりと、CGIプログラムには必須の機能です。

ファイルの読み込み

今回、CGIプログラムから読み込むファイルを data.txt とします。data.txt には、以下の内容が記録されているものとします。

ファイルの読み込み

Perlでファイルを開く場合、open という関数を使用します。使い方は以下のとおりです。

open(ファイルハンドル名, "ファイル名");

ファイルハンドルとは、ファイルのニックネームのようなものです。一度 open で開いたファイルは、それ以降ここで指定したファイルハンドル名で扱うことになります。ファイル名には、開きたいファイルの名前を指定します。

開いたファイルから実際にデータ変数に読み込むには、以下のように記述します。

$data = <ファイルハンドル名>;

ファイルハンドル名を <> で囲い、左辺に読込先の変数を指定します。<> は行入力演算子と呼ばれるもので、ファイルの内容を読み込む際に使用します。ファイルハンドル名には open でファイルを開くときに指定したファイルハンドル名を記述します。これで data.txt の内容が一行 $data に読み込まれます。

また、一度開いたファイルを閉じるには、close という関数を使用します。

close(ファイルハンドル名);

ファイルハンドルには、open でファイルを開くときに指定したファイルハンドル名を記述します。

ファイルから一行読み込む

以下に、実際にファイルを読み込んでその内容を表示するプログラムを記載します。

#!/usr/local/bin/perl

print "Content-Type: text/html; charset=Shift_JIS\n\n";
print "<html>\n";
print "<head><title>サンプル</title></head>\n";
print "<body>\n";

open(FH, "data.txt");
$data = <FH>;
close(FH);

print "<p>ファイルの内容は、$dataです。</p>\n";
print "</body>\n";
print "</html>\n";

exit;

これを実行すると、ブラウザに ファイルの内容は、ファイルの読み込みです。 と表示されます。ファイルを開いて読み込んでいるのは

open(FH, "data.txt");
$data = <FH>;
close(FH);

の部分です。data.txtFH というファイルハンドル名で開き、ファイルの内容を $data に読み込んでいます。そして読み込みができたら、そのファイルを閉じています。

ファイルから複数行読み込む(その1)

ファイルの読み込みが確認できたら、data.txt の内容を

再度ファイルの読み込み
複数行のファイルを
読み込みます。

として再度読み込ませてみてください。ブラウザに ファイルの内容は、再度ファイルの読み込みです。 と表示されたかと思います。すべての内容が表示されていませんね。

$data = <ファイルハンドル名>;

ではファイルの内容を先頭から一行読み込むのみなので、複数行のファイルを読み込む場合は少し工夫が必要です。方法はいくつかありますが、ここではまず

  1. 変数ではなく、配列にデータを読み込ませる。
  2. 配列の内容を foreach で一行ずつ表示させる。

という方法を使用します。具体的には以下のようになります。

#!/usr/local/bin/perl

print "Content-Type: text/html; charset=Shift_JIS\n\n";
print "<html>\n";
print "<head><title>サンプル</title></head>\n";
print "<body>\n";
print "<p>ファイルの内容は、<br>\n";

open(FH, "data.txt");
@file = <FH>;
close(FH);

foreach $data (@file) {
  print "$data<br>";
}

print "です。</p>\n";
print "</body>\n";
print "</html>\n";

exit;

これを実行すると、ブラウザに

ファイルの内容は、
再度ファイルの読み込み
複数行のファイルを
読み込みます
です。

と表示されます。ファイルハンドルの内容を配列に読み込ませると、配列の各要素にファイルの内容が1行ずつ格納されます。つまり、@file には data.txt の内容がすべて代入されるので、それを foreach で順に表示しています。

ファイルから複数行読み込む(その2)

上の方法で複数行のファイルを読み込むことができますが、この方法には欠点があります。

一旦すべてのデータを配列に読み込むため、ファイルに書かれた内容が何千行にもなる場合、メモリを大量に消費してしまいます。(実行速度が遅くなります。)このような場合、以下のようにすると負荷を軽減できます。

#!/usr/local/bin/perl

print "Content-Type: text/html; charset=Shift_JIS\n\n";
print "<html>\n";
print "<head><title>サンプル</title></head>\n";
print "<body>\n";
print "<p>ファイルの内容は、<br>\n";

open(FH, "data.txt");
while ($data = <FH>) {
  print "$data<br>";
}
close(FH);

print "です。</p>\n";
print "</body>\n";
print "</html>\n";

exit;

$data = <FH> とするとファイルの内容を一行読み込むことができますが、これを2回・3回…と繰り返すと二行目・三行目…と順に読み込むことができます。これを利用して「ファイルハンドルから一行読み込むことができれば print "$data<br>"; を実行する」という処理にしています。つまり、最終行に達するまでファイルの内容を表示する事になります。

この方法にすれば一行ずつしかデータを読み込まないため、メモリの消費を抑える事ができます。特に理由が無ければ、通常はこのように処理した方がいいですが、「ファイルの内容を配列に読み込んで、配列操作関数でデータを加工する」という場合もあるため、一概には言えません。

ただ、単純にファイルの内容を画面に表示するような場合は、配列を使用しないほうがいいでしょう。

ファイルを読み込めなかったときにエラーを表示する

これまでのプログラムでは、ファイルが存在しないなどの理由で読み込みができなかった場合でも普通に実行されてしまいます。(もちろん、ファイルの内容は表示されません。)ですが、ファイルの読み込みに失敗したときはエラーメッセージを表示させたほうが分りやすいです。

ファイルが読み込めなかった場合にエラーメッセージを表示するプログラムは以下のようになります。

#!/usr/local/bin/perl

print "Content-Type: text/html; charset=Shift_JIS\n\n";
print "<html>\n";
print "<head><title>サンプル</title></head>\n";
print "<body>\n";

if (open(FH, "data.txt")) {
  print "<p>ファイルの内容は、<br>\n";

  while ($data = <FH>) {
    print "$data<br>";
  }
  close(FH);

  print "です。</p>\n";
} else {
  print "ファイルを読み込めません。";
}

print "</body>\n";
print "</html>\n";

exit;

if を使用して条件分岐をさせています。if (open(FH, "data.txt")) は、『ファイルを正しく開くことができれば』という条件になっています。開くことができればファイルの内容を読み出して表示し、できなければ print "ファイルを読み込めません。"; が実行されます。

これで、ファイルの読み込みに失敗したときは ファイルを読み込めません。 と表示されるようになります。

ファイルへの書き込み

ファイルの内容を読み込むことができたので、今度はファイルへの書き込みを行ってみます。ファイルに書き込むには、以下のように記述します。

open(FH, ">data.txt");
print FH "書き込みのテスト。";
close(FH);

ファイルの読み込みと同様ファイルを開くのですが、ファイルに書き込みを行う場合は書き込みモードで開く必要があります。開きたいファイルの前に > を追加すると書き込みモードになります。(> が無ければ読み込みモードと解釈され、ファイルに書き込むことはできません。)

書き込みには print 関数を使用します。これまで画面に文字を表示する際に利用してきましたが、この関数でファイルに書き込むこともできます。

print ファイルハンドル名 書き込みたい内容;

とすると、指定したファイルハンドルに任意の内容を書き込むことができます。なお、複数行の内容を書き込みたい場合は、

print FH "書き込みのテスト。\n複数行の内容を\n書き込みます。";

このように改行文字付きでファイルに書き込みます。以下に、ファイルへの書き込みを行う具体的なプログラムを記載します。

#!/usr/local/bin/perl

print "Content-Type: text/html; charset=Shift_JIS\n\n";
print "<html>\n";
print "<head><title>サンプル</title></head>\n";
print "<body>\n";

$data = "書き込みのテスト。\n複数行の内容を\n書き込みます。";

if (open(FH, ">data.txt")) {
  print FH $data;
  close(FH);

  print "書き込みが完了しました。";
} else {
  print "ファイルを開けません。";
}

print "</body>\n";
print "</html>\n";

exit;

書き込みが成功すると、ブラウザに 書き込みが完了しました。 と表示されます。ファイルに書き込む内容は、あらかじめ $data に代入しています。