Search A.I.
Menu
ホーム

メールマガジン ホームページプログラミングテク

Windowsテク
Javaアプレット サンプル
Java Q & A
JavaScript Q & A
Perl Q & A
Perl レッスン
PHP レッスン
PHPテク
MS-DOS コマンド集
UNIX コマンド集
SQL コマンド集
SEの基礎講座
WEBシステム開発受注します
]無料フォームメール送信サービス
リンク集
Perl レッスン

1. Perl の基礎
2. Perlの文法、条件式
3. Perlの文法、条件式 - 続き
4. 配列について
5. ハッシュ配列について
6. Perlの基礎 - 続き
7. 関数について
8. 関数について - 続き
9. 文字列操作関数
10. 配列操作関数
11. ファイル操作
12. ファイル操作 - 続き
13. パラメータの受け渡し
14. クッキーについて
15. 総合練習
16. メール送信
17. ファイルアップロード
18. パッケージの使用方法
19. MySQL
20. MySQL - 続き(1)
21. MySQL - 続き(2)
22. PostgreSQL
23. 総合練習
24. 総合練習解答



12. ファイル操作 - 続き

今日は、ファイル操作の続きのご説明をいたします。

■ファイル検査演算子
ファイルの状態、属性を確認する為にPerlではいろいろな演算子が用意されて
います。通常、条件文の中で、以下のように記述します。

検査演算子 ファイル名

検査演算子には、以下のようなものがあります。

-r 読み込み可能かどうか
-w 書き込み可能かどうか
-e ファイルが存在するかどうか
-z ファイルサイズが 0 であるかどうか
-s ファイルサイズが 0 でないかどうか
-f 通常ファイル(ディレクトリでない)かどうか
-d ディレクトリであるかどうか
-T ファイルがテキストファイルかどうか
-B ファイルがバイナリファイルかどうか

以下に使用例を記述します。

-----------------------------------------------------------------
if ( -e "sample.txt" ) {
print "sample.txt は存在します。";
} else {
print "sample.txt 存在しません。";
}
-----------------------------------------------------------------

■ファイル操作関数
これまでに、いくつかのファイル操作関数が出てきましたが、その他のファイル
操作関数をご紹介します。

eof(FH) ファイルを最後まで読み込んだかを確認します。
stat(FH) ファイル情報を配列で取得します。
unlink($fname1,$fname2, ・・・・)
指定したファイルを削除します。
rename($fname1,$fname2)
ファイル名を$fname1から$fname2に変更します。

以下にサンプルを記述します。

-----------------------------------------------------------------
$filename = "test.txt";

# ファイルオープン
if (!open(FH, "< $filename")) {
print "ファイルオープンに失敗しました。($filename)";
exit;
}
@data = <FH>;

# ファイルの読み込み完了確認
if (eof(FH)) {
print "End of file.";
}

# ファイル情報の取得
@file_info = stat(FH);
foreach (@file_info) {
print $_;
}

# ファイルクローズ
close(FH);

$filename2 = "test2.txt";
# ファイル名の変更
if (!rename($filename, $filename2)) {
print "リネーム失敗";
}

# ファイルの削除
unlink($filename2);

-----------------------------------------------------------------

eof()は、読み込みが完了していると、真を返します。End Of Fileの略です。

stat()は、statusの略で、ファイル情報を返します。第1引数にファイルハンドル
またはファイル名を指定します。戻り値は、ファイル情報の配列になります。
ファイル情報は、以下のものになります。

添字 取得される内容
0 ファイルシステムのデバイス情報
1 Iノード番号
2 ファイルモード(パーミッション等)
3 対象ファイルのリンク数
4 対象ファイルの所有書のユーザID
5 対象ファイルのグループのグループID
6 デバイス識別子
7 ファイルサイズ(バイト数)
8 最終アクセス時間
9 最終変更時間
10 最終 I ノード変更時間
11 最適ブロックサイズ
12 割当てられているブロック数

ファイル情報で必要になるのは、ファイルサイズや最終変更時間くらいだと
思います。最終変更時間は、UNIXタイムスタンプと言って、1970年 1月 1日を
0 として、その日時まで 1 秒ずつカウントした値が入ります。

UNIXタイムスタンプは、ここではあまり説明しませんが、時間の計算でよく
使用しますので、覚えておくと良いでしょう。

rename()は、ファイル名を変更します。第1引数に、変更するファイル名、
第2引数に変更後のファイル名を指定します。成功すると、真が返ってきます。

unlink()は、ファイルを削除します。複数の引数を指定することで、複数の
ファイルを削除することができます。戻り値は、削除したファイルの数に
なります。

rename()やunlink()は、ファイルオープンしてからクローズしていない状態で
実行するとエラーになりますので、注意してください。

■ファイルロック
ファイル書き込み中に、別のユーザのアクセスによって、同時に同じファイルを
更新されると、ファイルが壊れたり、中身が消えたりしてしまいます。

そこで、誰かがファイル書き込み中のときは、ファイルロックして、他の人が
ファイルを更新できないようにします。

ここでは、簡単なファイルロック方法をご紹介します。
ファイルロックを行うには、flock()関数を使用します。
ただし、サーバによっては、flock関数が使用できないので、注意してください。

flock(FH, $lock) ファイルのロックや開放を行います。

第2引数には、設定するロック状態のフラグを指定します。

LOCK_SH : 1 共有ロック(読み込みは可能)
LOCK_EX : 2 排他ロック
LOCK_NB : 4 ロックなし
LOCK_UN : 8 ロック解除

サーバによっては、これらの定数が定義されていない場合がありますが、数値を
直接指定しても同じです。。

-----------------------------------------------------------------
# 書き込みモードでファイルオープン
open(FH, "> $filename") or exit;

# ファイルロック
flock(FH, LOCK_EX);

# ファイル書き込み
print FH "TEST";

# ファイルロック解除
flock(FH, LOCK_UN);

# ファイルクローズ
close(FH);
-----------------------------------------------------------------

これで、一応ファイルロックされますが、これはまだ完璧ではありません。
ファイルオープン後にファイルロックしていますが、この処理の間でアクセス
があった場合に、同時にファイルオープンされてしまう可能性があるからです。

完全に回避するには、ロック用の一時ファイルを作成する方法がありますが、
これについては、別の機会にご説明します。

ここでは、上のサンプルを、さらに安全にしたものをご紹介します。

-----------------------------------------------------------------
# 追加書き込みモードでファイルオープン
open(FH, ">> $filename") or exit;

# ファイルロック
flock(FH, LOCK_EX);

#// ファイルの中身を削除
truncate(FH, 0);

# ファイル書き込み
print FH "TEST";

# ファイルロック解除
flock(FH, LOCK_UN);

# ファイルクローズ
close(FH);
-----------------------------------------------------------------

先ほどとの違いは、追加書き込みで開いてロックした後に、ファイル内容を削除
しているという点です。

truncate()は、第2引数で指定したバイト数にファイルを切り詰める関数です。
サンプルの場合、0 バイトに切り詰めることで、ファイル内容を削除しています。
ただし、このtruncate()もサーバによっては使用できない場合があるので、
注意してください。

ファイル書き込みモードでオープンしてしまうと、一旦ファイル内容がクリア
されてしまいますので、追加モードで開いてからロックした方が安全と言えます。

 

★今日のまとめサンプルプログラム
-----------------------------------------------------------------
#! /usr/local/bin/perl

print "Content-type:text/html\n\n";

print << "END_OF_HTML";
<HTML>
<BODY>
END_OF_HTML

$filename = "test.txt";

# ファイルの存在チェック
if (!(-e $filename)) {
open(FH, "> $filename") || print "open err";
close(FH);
}

# 読み込みモードでファイルオープン
open(FH, "< $filename") || print "open err";

# ファイル内容の取得
$data = <FH>;

# ファイルが読み込めたか
if (!(eof(FH))) { print "eof err"; }

# ファイルクローズ
close(FH);

# ファイル情報の取得
@file_info = stat($filename);
foreach (@file_info) {
print $_ . "<br>";
}

# ファイルのリネーム
$filename2 = "test2.txt";
if (!(rename($filename, $filename2))) { print "rename err"; }

# 追加モードでファイルオープン
open(FH, "> $filename2") || print "open err";

# ファイルロック
flock(FH, LOCK_EX);

# 追加モードで開いてロックした後で、ファイル内容を消した方が安全
truncate(FH, 0);

# ファイル書き込み
print FH "TEST\n";

# ファイルロック解除
flock(FH, LOCK_UN);

# ファイルクローズ
close(FH);

print << "END_OF_HTML";
</BODY>
</HTML>

END_OF_HTML

exit;
-----------------------------------------------------------------

■解説
通常の処理で、ファイルが最後まで読み込めなくなるようなことはないので、
毎回eof()関数で読み込みチェックを行う必要はありません。

ファイルロックの部分は、追加モードで開きますが、ファイル内容は削除
しますので、上書きと同じ処理になります。
実際に実行すると、test.txtの内容は消えてしまうので、注意してください。

test.txtがない場合は、空のファイルを書き込みオープンすることで、新しく
作成されます。

エラー時の処理などは、かなり省略していますが、実際にプログラムを書く
ときは、サイト毎に共通のエラー処理を決めるのが普通です。

 

★課題
1. 以下の処理を行うプログラムを作成してください。
(1) "test.tmp"ファイルの存在を判別
(2) "test.tmp"が存在する場合は、"エラー"を表示して終了
(3) "test.tmp"に現在時刻を書き込む(yyyy/mm/dd hh:mm:ss)
(4) "test.tmp"のファイルサイズが 0 かどうかを判別
(5) "test.tmp"のファイルサイズを取得
(6) "test.tmp"を削除する

2. 前回作成したアクセスカウンタのプログラムを変更し、ファイル書き込み時に
ファイルロックを行うように変更してください。

 

★前回の課題の解答
1. 簡易的なアクセスカウンタを作成してください。

→下のサンプルを参照してください。

-----------------------------------------------------------------
#! /usr/local/bin/perl

print "Content-type:text/html\n\n";

print << "END_OF_HTML";
<HTML>
<BODY>
END_OF_HTML

$filename = './count.txt';

# ファイル読み込み
if (!open(FH, "< $filename")) {
print "ファイルオープンに失敗しました。($filename)";
exit;
}

# データの取得
$cnt = <FH>;

# ファイル開放
close(FH);

if ($cnt eq '') { $cnt = 0;}

$cnt = $cnt + 1;

# ファイル書き込み
if (!open(FH, "> $filename")) {
print "ファイルオープンに失敗しました。($filename)";
exit;
}

# データの書き込み
print FH $cnt;

# ファイル開放
close(FH);

print $cnt;

print << "END_OF_HTML";
</BODY>
</HTML>

END_OF_HTML

exit;
-----------------------------------------------------------------

■解説
"count.txt"というファイルを作成して、CGIと同じ場所に置いておきます。
UNIXの場合は、書き込みの権限を与える必要があります。

このファイルを読み込んで、一旦閉じて、書き込みで開きなおすという処理を
行います。

if ($cnt eq '') { $cnt = 0;}
の部分は、なくても構いませんが、ファイルの中身がない場合は、0 から
カウントを始めます。

ファイルがない場合の処理もあると親切ですね。




前の章へ 次の章へ


このエントリーをはてなブックマークに追加


OfficeLance

お問い合わせはこちらから