ファイルが存在するかどうかを判断するときに、tryステートメントを使用すると「競合状態」をどのように回避できますか?
非常に賛成の 回答 (更新:削除されました)は、os.path.exists()
を使用すると、他の方法では存在しない機会が生まれることを意味しているように思われるため、質問しています。
与えられた例は次のとおりです。
_try:
with open(filename): pass
except IOError:
print 'Oh dear.'
_
しかし、私はそれがどのように競合状態を回避するのかを理解していません:
_if not os.path.exists(filename):
print 'Oh dear.'
_
os.path.exists(filename)
を呼び出すと、攻撃者はファイルに対して、まだ実行できなかったことをどのように実行できますか?
もちろん、競合状態は、プログラムとファイルを操作する他のコードの間です(競合状態には、常に少なくとも2つの並列プロセスまたはスレッドが必要です。詳細については this を参照してください)。つまり、open()
の代わりにexists()
を使用すると、実際には次の2つの状況でのみ役立つ可能性があります。
exists()
は1つのチェックを実行するだけです。ファイルが存在する場合、exists()
がTrue
を返した1マイクロ秒後に削除される可能性があります。ファイルがない場合は、すぐに作成できます。
ただし、open()
は、ファイルの存在をテストするだけでなく、ファイルを開きます(そして、これら2つのアクションをアトミックに実行するため、チェックとオープンの間に何も起こりません)。通常、ファイルは誰かが開いている間は削除できません。つまり、with
の内部では、完全に確信している可能性があります。ファイルは開いているので、実際に存在しています。これはwith
内でのみ当てはまり、ファイルはwith
ブロックが終了した直後に削除される可能性がありますが、ファイルがwith
内に存在する必要があるコードを配置すると、コードが失敗しないことが保証されます。
使用例は次のとおりです。
try:
with open('filename') as f:
do_stuff_that_depends_on_the_existence_of_the_file(f)
except IOError as e:
print 'Trouble opening file'
アクセス権を持ってファイルを開いている場合、OSはファイルが存在することを保証します。そうでない場合、エラーで失敗します。アクセスが排他的である場合、ファイルをめぐって競合している他のプロセスは、あなたによってブロックされるか、あなたをブロックします。
try
は、ファイルを開く動作のエラーまたは成功を検出するための単なる方法です。PythonのファイルI/O APIには通常、戻りコードがないためです(例外)代わりに使用されます)。したがって、実際に質問に答えるには、競合状態を回避するのはtry
ではなく、open
です。Cでも基本的に同じです(Pythonベース)ですが、例外はありません。詳細については、 this をお読みください。
Tryブロック内のファイルへのアクセスに依存するコードを実行することをお勧めします。ファイルを閉じると、その存在は保証されなくなります。
os.path.exists
を呼び出すと、ファイルが存在する場合と存在しない場合がある瞬間のスナップショットが得られるだけであり、os.path.exists
が戻った後はファイルの存在を知ることはできません。悪意のあるコードまたは予期しないロジックにより、予期しないときにファイルが削除または変更される可能性があります。頭を回して、車を運転する前に道路が空いていることを確認するのと似ています。頭を後ろに向けると、もう見ていない場所で何が起こっているのかを推測するだけです。ファイルを開いたままにしておくと、運転中に(善悪を問わず)不可能な、拡張された一貫性のある状態が保証されます。 :)
try/open
のスナップショットの性質のため、os.path.exists
を使用するのではなく、ファイルが存在しないことを確認するという提案はまだ不十分です。残念ながら、すべての場合にファイルがディレクトリに作成されるのを防ぐ方法はわかりません。そのため、ファイルが存在しないのではなく、存在するかどうかを確認するのが最善だと思います。
あなたが求めているのは、次のような特定の競合状態だと思います。
この場合の「保護」方法は、すべてのファイル処理コードをtry
ブロックに配置することです。いずれかの時点でファイルにアクセスできなくなったり破損したりすると、ファイル操作が「正常に」失敗する可能性があります。 catch
ブロック経由。
もちろん、最近のOSの場合、これはとにかく発生しません。ファイルが「削除」されると、ファイルで開いているすべてのハンドルが解決(解放)されるまで削除は行われません。