17

ある場所から別の場所にファイルをコピーする必要があります。ファイルが宛先にすでに存在する場合(上書きなし)、例外をスローする(または少なくとも何らかの方法で認識する)必要があります。

最初にos.path.exists()で確認できますが、確認してからコピーするまでの短い時間でファイルを作成できないことが非常に重要です。

これを行う組み込みの方法はありますか、それともアクションをアトミックとして定義する方法はありますか?

4

2 に答える 2

18

実際、すべてのアクターが同じ方法でこれを行うのであればこれを原子的かつ安全に行う方法があります。これはロックフリーのモグラたたきアルゴリズムの適応であり、完全に些細なことではないので、一般的な答えとして「いいえ」を自由に選んでください;)

何をすべきか

  1. ファイルがすでに存在するかどうかを確認してください。もしそうなら停止します。
  2. 一意のIDを生成する
  3. ソースファイルを一時的な名前(たとえば、)でターゲットフォルダにコピーします<target>.<UUID>.tmp
  4. コピーの名前を†</sup>変更します<target>-<UUID>.mole.tmp
  5. パターンに一致する他のファイルを探します <target>-*.mole.tmp
    • それらのUUIDがあなたのUUIDよりも大きい場合は、それを削除してみてください。(なくなっても心配しないでください。)
    • それらのUUIDが自分のUUIDよりも小さい場合は、自分のUUIDを削除してみてください。(繰り返しますが、なくなっても心配しないでください。)これからは、UUIDを自分のものであるかのように扱います。
  6. 宛先ファイルがすでに存在するかどうかをもう一度確認してください。その場合は、一時ファイルを削除してみてください。(なくなっても心配しないでください。手順5でUUIDが変更されている可能性があることに注意してください。)
  7. 手順6でまだ削除を試みていない場合は、一時ファイルの名前を最終的な名前に変更してみてください<target>。(なくなっても心配しないでください。手順5に戻ってください。)

完了です。

使い方

各候補ソースファイルがその穴から出てくるほくろであると想像してください。途中で、他のほくろが完全に出現していないことを確認する前に、一時停止して競合するほくろを地面に叩き返します。これを頭の中で実行すると、たった1つのほくろだけが完全にそれを達成することがわかるはずです。このシステムがライブロックするのを防ぐために、どのモグラがどれを叩くことができるかについての全順序を追加しますバム! 博士論文 ロックフリーアルゴリズム

†</sup>ステップ4は不要に見えるかもしれません。そもそも、その名前を使用しないのはなぜですか。 ただし、別のプロセスがステップ5であなたのほくろ ファイルを「採用」し、ステップ7でそれを勝者にする可能性があるため、まだ内容を書き出していないことが非常に重要です。同じファイルシステムでの名前の変更はアトミックであるため、手順4は安全です。

于 2015-01-22T14:13:46.550 に答える
13

これを行う方法はありません。ファイルのコピー操作は決してアトミックではなく、それらを作成する方法はありません。

ただし、ファイルをランダムな一時的な名前で書き込んでから、名前を変更することはできます。名前の変更操作はアトミックである必要があります。ファイルがすでに存在する場合、名前の変更は失敗し、エラーが発生します。

[EDIT2] rename()は、同じファイルシステムで実行する場合にのみアトミックです。安全な方法は、宛先と同じフォルダーに新しいファイルを作成することです。

[編集]名前変更が常にアトミックであるかどうか、および上書き動作については多くの議論があります。だから私はいくつかのリソースを掘り起こしました。

Linuxでは、宛先が存在し、ソースと宛先の両方がファイルである場合、宛先はサイレントに上書きされます(マニュアルページ)。だから私はそこで間違っていました。

ただし、rename(2)問題が発生した場合でも元のファイルまたは新しいファイルのいずれかが有効であることが保証されるため、データを破損できないという意味で操作はアトミックです。2つのプロセスが同時に同じ名前変更を行うのを防ぎ、結果を予測できるという意味で、アトミックではありません。1つは勝ちますが、どちらかはわかりません。

Windowsでは、別のプロセスが現在ファイルを書き込んでいる場合、書き込み用にファイルを開こうとするとエラーが発生するため、Windowsの利点の1つはここにあります。

操作がディスクに書き込まれているときにコンピュータがクラッシュした場合、ファイルシステムの実装によって、破損するデータの量が決まります。これについてアプリケーションができることは何もありません。だからもう泣き言をやめなさい:-)

また、これと同じようにうまく機能するアプローチは他にありません。

代わりにファイルロックを使用できます。しかし、それはすべてをより複雑にし、追加の利点をもたらさないでしょう(一部の人々が何らかの理由で大きな利点と見なすより複雑であることに加えて)。また、ファイルがネットワークドライブ上にある場合は、多くの優れたコーナーケースを追加します。

ファイルがすでに存在する場合に関数が失敗するopen(2)モードで使用できます。O_CREATしかし、それでも、ファイルを削除して独自のコピーを書き込む2番目のプロセスを妨げることはありません。

または、ディレクトリの作成もアトミックである必要があるため、ロックディレクトリを作成できます。しかし、それでもあまり買わないでしょう。ロックコードを自分で作成し、災害が発生した場合にロックディレクトリを本当に常に削除することを100%確実にする必要があります。これはできません。

于 2012-07-23T14:46:04.717 に答える