11. ファイル操作 - 続き
今日は、ファイル操作の続きのご説明をいたします。
■ファイル操作関数
これまでに、いくつかのファイル操作関数が出てきましたが、その他のファイル
操作関数をご紹介します。
file_exists($fname) ファイルの存在を確認します。
filesize($fname) ファイルのサイズを確認します。
is_file($fname) ファイルかどうかを判定します。
is_dir($dir) ディレクトリかどうかを判定します。
is_readable($fname) ファイルが読み込み可能かを確認します。
is_writable($fname) ファイルが書き込み可能かを確認します。
unlink($fname1) 指定したファイルを削除します。
rename($fname1,$fname2)
ファイル名を$fname1から$fname2に変更します。
copy($fname1,$fname2)
ファイル$fname1を$fname2のファイル名でコピーします。
以下にサンプルを記述します。
-----------------------------------------------------------------
$filename = "test.txt";
// ファイルの存在確認
if (!file_exists($filename)) {
print "ファイルが見つかりません。 ".$filename;
exit;
}
// ファイルかどうかの判定
if (is_file($filename)) {
print $filename."はファイルです。<br>";
}
if (is_dir($filename)) {
print $filename."はディレクトリです。";
exit;
}
// 読み込み・書き込みの判定
if (is_readable($filename)) {
print $filename."は読み込み可能です。<br>";
}
if (is_writable($filename)) {
print $filename."は書き込み可能です。<br>";
}
// ファイルサイズ取得
print filesize($filename);
$filename2 = "test2.txt";
// ファイル名の変更
if (!rename($filename, $filename2)) {
print "リネーム失敗";
exit;
}
$filename3 = "test3.txt";
// ファイルのコピー
if (!copy($filename2, $filename3)) {
print "コピー失敗";
exit;
}
// ファイルの削除
unlink($filename2);
-----------------------------------------------------------------
file_exists()は、ファイルの存在を確認します。ディレクトリの存在確認にも
使えますが、ディレクトリなのかファイルなのかは、この関数では分かりません。
is_dir()またはis_file()関数を使用すれば、ファイルかディレクトリかの
判定ができます。
is_readable()は、ファイルが存在して、かつ読み込み可能な場合に真を返します。
is_writable()も同様に、ファイルが存在して、かつ書き込み可能な場合に、真を
返します。
rename()は、ファイル名を変更します。第1引数に、変更するファイル名、
第2引数に変更後のファイル名を指定します。成功すると、真が返ってきます。
copy()は、ファイルをコピーします。第1引数に、コピー元のファイル名、
第2引数にコピー先のファイル名を指定します。成功すると、真が返ってきます。
unlink()は、ファイルを削除します。成功すると真、失敗すると偽が返ってきます。
rename()やunlink()などは、ファイルオープンしてからクローズしていない状態で
実行するとエラーになりますので、注意してください。
上記を全て実行すると、test.txtのファイルがあった場合、test2.txtにリネーム
され、test3.txtにコピーされ、test2.txtが削除されますので、結局test3.txt
だけが残り、ファイルの情報が出力されます。
■ファイルロック
ファイル書き込み中に、別のユーザのアクセスによって、同時に同じファイルを
更新されると、ファイルが壊れたり、中身が消えたりしてしまいます。
そこで、誰かがファイル書き込み中のときは、ファイルロックして、他の人が
ファイルを更新できないようにします。
ここでは、簡単なファイルロック方法をご紹介します。
ファイルロックを行うには、flock()関数を使用します。
ただし、サーバによっては、flock関数が使用できないので、注意してください。
flock($fh, $lock) ファイルのロックや開放を行います。
第2引数には、設定するロック状態のフラグを指定します。
LOCK_SH : 1 共有ロック(読み込みは可能)
LOCK_EX : 2 排他ロック
LOCK_NB : 4 ロックなし
LOCK_UN : 8 ロック解除
PHPのバージョンによっては、これらの定数が定義されていない場合がありますが、
数値を直接指定しても同じです。。
-----------------------------------------------------------------
// 書き込みモードでファイルオープン
$fh = fopen($filename, 'w');
if (!$fh) {
print "ファイルオープンに失敗しました。 ".$filename;
exit;
}
// ファイルロック
flock($fh, LOCK_EX);
// ファイル書き込み
fwrite($fh, "TEST");
// ファイルロック解除
flock($fh, LOCK_UN);
// ファイルクローズ
fclose($fh);
-----------------------------------------------------------------
これで、一応ファイルロックされますが、これはまだ完璧ではありません。
ファイルオープン後にファイルロックしていますが、この処理の間でアクセス
があった場合に、同時にファイルオープンされてしまう可能性があるからです。
完全に回避するには、ロック用の一時ファイルを作成する方法がありますが、
これについては、別の機会にご説明します。
ここでは、上のサンプルを、さらに安全にしたものをご紹介します。
-----------------------------------------------------------------
// 追加書き込みモードでファイルオープン
$fh = fopen($filename, 'a');
if (!$fh) {
print "ファイルオープンに失敗しました。 ".$filename;
exit;
}
// ファイルロック
flock($fh, LOCK_EX);
// ファイルの中身を削除
ftruncate($fh, 0);
// ファイル書き込み
fwrite($fh, "TEST");
// ファイルロック解除
flock($fh, LOCK_UN);
// ファイルクローズ
fclose($fh);
-----------------------------------------------------------------
先ほどとの違いは、追加書き込みで開いてロックした後に、ファイル内容を削除
しているという点です。
ftruncate()は、第2引数で指定したバイト数にファイルを切り詰める関数です。
サンプルの場合、0 バイトに切り詰めることで、ファイル内容を削除しています。
ただし、このftruncate()もサーバによっては使用できない場合があるので、
注意してください。
ファイル書き込みモードでオープンしてしまうと、一旦ファイル内容がクリア
されてしまいますので、追加モードで開いてからロックした方が安全と言えます。
★今日のまとめサンプルプログラム
-----------------------------------------------------------------
<HTML>
<BODY>
<?
$filename = "test.txt";
// ファイルの存在確認
if (!file_exists($filename)) {
print "ファイルが見つかりません。 ".$filename;
exit;
}
// ファイルかどうかの判定
if (!is_file($filename)) {
print $filename."はファイルではありません。";
exit;
}
// 読み込み・書き込みの判定
if (!is_readable($filename)) {
print $filename."は読み込み可能ではありません。";
exit;
}
if (!is_writable($filename)) {
print $filename."は書き込み可能ではありません。";
exit;
}
// ファイルサイズ取得
$fsize = filesize($filename);
if ($fsize == 0) {
// 追加書き込みモードでファイルオープン
$fh = fopen($filename, 'a');
if (!$fh) {
print "ファイルオープンに失敗しました。 ".$filename;
exit;
}
// ファイルロック
flock($fh, LOCK_EX);
// ファイルの中身を削除
ftruncate($fh, 0);
// ファイル書き込み
fwrite($fh, "This is a sample file.\n");
// ファイルロック解除
flock($fh, LOCK_UN);
// ファイルクローズ
fclose($fh);
}
?>
</BODY>
</HTML>
-----------------------------------------------------------------
■解説
この処理は、text.txtファイルの存在を確認し、読み込み・書き込み可能で、
かつファイルサイズが 0 の場合に、ファイルロックして書き込みを行って
います。
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. 簡易的なアクセスカウンタを作成してください。
→下のサンプルを参照してください。
-----------------------------------------------------------------
<HTML>
<BODY>
<?
$filename = './count.txt';
// 読み込みモードでファイルオープン
$fh = fopen($filename, 'r');
if (!$fh) {
print "ファイルオープンに失敗しました。 ".$filename;
exit;
}
// ファイル読み込み
while (!feof($fh)) {
$cnt = fgets($fh);
}
// ファイルクローズ
fclose($fh);
if ($cnt == "") {
$cnt = 0;
}
$cnt = $cnt + 1;
// 書き込みモードでファイルオープン
$fh = fopen($filename, 'w');
if (!$fh) {
print "ファイルオープンに失敗しました。 ".$filename;
exit;
}
// ファイル書き込み
fwrite($fh, $cnt);
// ファイルクローズ
fclose($fh);
print $cnt;
?>
</BODY>
</HTML>
-----------------------------------------------------------------
■解説
"count.txt"というファイルを作成して、PHPファイルと同じ場所に置いておきます。
UNIXの場合は、書き込みの権限を与える必要があります。
このファイルを読み込んで、一旦閉じて、書き込みで開きなおすという処理を
行います。
if ($cnt == "") {
$cnt = 0;
}
の部分は、なくても構いませんが、ファイルの中身がない場合は、0 から
カウントを始めます。
ファイルがない場合の処理もあると親切ですね。
|