2

次のような単純なfopen/fwrite()を使用する場合:

$ref = @fopen('/path/to/file', 'x+b'); // returns false if already exists
if ($ref) {
    fwrite($ref, 'A');
    sleep(5);
    fwrite($ref, 'B');
}

スリープ中に他のプロセスがファイルを削除した場合に、ファイルポインタがまだ有効であることをどのように確認できますか?

単純なis_file()チェックを使用することを検討しましたが、別のプロセスがunlink()を実行してから、同じパスで新しいファイルを作成したかどうかはわかりません。

参考までに、ファイルがunlink()されていても、fwriteはtrueを返すようです。

編集:明確にするために、sleep(5)は単なるランダムな時間であり、競合状態の場合は数ミリ秒になる可能性があります。

4

4 に答える 4

4

テストを行ったところ、それfstatが解決策のようです。

$fd = fopen("/path/to/file", "w");
var_dump(fstat($fd)); // shows ['nlink'] => int(1)
sleep(60);
// in a shell console, remove the file
var_dump(fstat($fd)); // shows ['nlink'] => int(0)
于 2012-11-19T09:51:43.073 に答える
2

fopen()を再度実行する必要があります。Linuxシステムでは、まだ参照しているので、削除されたファイルに書き込むことができます。それを閉じると、ファイルは最終的に削除されます。

プロセスが待機する必要がある場合は、閉じてから、スリープの間にファイルを開きます

于 2012-11-19T09:12:45.837 に答える
2

ファイルへのハンドルを持っている場合は、それを気にする必要はありません。ファイルシステムがそれを処理しています。

編集

ハンドルを閉じるかスクリプトが終了しない限り、ハンドルは有効です。ファイルの削除はハンドルの有効性とはまったく関係がないため、ロックされます。つまり、大きなファイル(1GB)を作成し、ブラウザを使用してフェッチを開始することで簡単に確認でき、他のプロセスから「安全に」削除できるようになります。lsそして、これは、ファイルが既存のものとしてリストされなくなるようなツールであっても、フェッチに影響を与えません。ダウンロードが失敗した場合、httpdは開いたハンドルを閉じ、他のプロセスがハンドルを保持していない場合、物理的にディスクスペースを解放するため、「安全に」と書きました。ただし、少なくとも1つの参照がある限り、データはディスクに残ります(-のようなツールを使用してディスクの空き容量をdf順番に確認することで簡単に確認できます。

create 1GB file
df
start download
rm file
df

2番目dfは、ディスクスペースが1番目のものと同じであることを示します(もちろん、他のファイル操作が発生しなかったと仮定します)。ダウンロードを停止して、dfもう一度やり直してください。空き容量は1GB以上になりました。

WindowsのFSでは開いているファイルを削除できませんが、これは実装の問題であり、技術的な制限ではないことに注意してください。* nix上のほとんどの(それぞれではないにしても)FSは、これを問題なく処理します。

于 2012-11-19T09:12:57.313 に答える
0

多くの精度を追加するために:fopen()ロックは、ファイルを開いたタイプによって異なります。wロックしw+ます-、、はロックraませr+ん(デフォルト)。ただし、ファイルを他の場所で使用できないようにしたい場合は、この関数flock()が役立つ場合があります。

ただし、本当にファイルをロックして5秒間何もしない必要がある場合は、回避策を見つけるのではなく、代わりに設計/実装に質問します。

于 2012-11-19T09:16:29.047 に答える