2012-09-04 16 views
9

ファイルがファイルウォッチャーフォルダにコピーされているとき、ファイルが完全にコピーされて使用できる状態になっているかどうかをどのように確認できますか?ファイルコピー中に複数のイベントが発生するためです。 (ファイルはFile.Copyを使用して別のプログラムでコピーされます)FileSystemWatcher - ファイルを使用する準備ができています

答えて

2

ファイルを書き込むときにこの問題が発生しました。ファイルが完全に書き込まれて閉じられる前にイベントが発生しました。

解決策は、一時ファイル名を使用して、ファイルの名前を変更した後に名前を変更することです。次に、ファイルの作成や変更イベントではなく、ファイルの名前変更イベントを監視します。

+1

他の誰かがあなたにファイルをプッシュしている場合(FTPなどのように)、ファイル名を変更する前にファイルを使用できる状態にしておく必要があります。 – Tacroy

1

注:この問題は、一般的なケースでは解決できません。ファイルの使用状況に関する事前の知識がなければ、他のプログラムがファイルで操作を完了したかどうかを知ることができません。

具体的なケースでは、File.Copyがどのような操作で構成されているかを把握できるはずです。

ほとんどの場合、目的のファイルは操作中にロックされます。この場合、単にファイルを開き、 "共有モード違反"の例外を処理することができます。

非常に信頼性の低いオプションですが、ファイルのサイズ範囲がわかっている場合は、コピーが完了するまでに妥当な遅延が生じることがあります。

また、「destination_file_name」をコピーして後で削除すると、コピー先のファイルが作成する「destination_file_name.COPYLOCK」のような別のファイルを作成することもできます。

9

私がこの問題に遭遇したとき、私が思いついた最善の解決策は、ファイルに対して排他的なロックを絶えず試みることでした。ファイルが書き込まれている間、ロックの試みは失敗し、本質的にはthisのメソッドに応答します。ファイルがそれ以上書き込まれないと、ロックは成功します。

残念ながら、これを実行する唯一の方法は、ファイルを開くときにtry/catchをラップすることです。これは私がうんざりさせるようにします。try/catchを使用することは常に苦痛です。しかし、その周りには何の方法もないように見えるので、私が使用し終わったのです。その答えにコードを変更する

は、トリックを行いますので、私はこのような何か使用して終了:ここ

private void WaitForFile(FileInfo file) 
{ 
    FileStream stream = null; 
    bool FileReady = false; 
    while(!FileReady) 
    { 
     try 
     { 
      using(stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None)) 
      { 
       FileReady = true; 
      } 
     } 
     catch (IOException) 
     { 
      //File isn't ready yet, so we need to keep on waiting until it is. 
     } 
     //We'll want to wait a bit between polls, if the file isn't ready. 
     if(!FileReady) Thread.Sleep(1000); 
    } 
} 
+3

回数を追加し、失敗したx回の試行後に試行を終了することができます。 – McGarnagle

1

することとの間にSleepで、倍のX番号にファイルへのアクセスを再試行します方法であり、試してみる。それは上のアクセス、アプリケーションの移動を取得したことがない場合:

private static bool GetIdleFile(string path) 
{ 
    var fileIdle = false; 
    const int MaximumAttemptsAllowed = 30; 
    var attemptsMade = 0; 

    while (!fileIdle && attemptsMade <= MaximumAttemptsAllowed) 
    { 
     try 
     { 
      using (File.Open(path, FileMode.Open, FileAccess.ReadWrite)) 
      { 
       fileIdle = true; 
      } 
     } 
     catch 
     { 
      attemptsMade++; 
      Thread.Sleep(100); 
     } 
    } 

    return fileIdle; 
} 

それはこのように使用することができます。もちろん...

private void WatcherOnCreated(object sender, FileSystemEventArgs e) 
{ 
    if (GetIdleFile(e.FullPath)) 
    { 
     // Do something like... 
     foreach (var line in File.ReadAllLines(e.FullPath)) 
     { 
      // Do more... 
     } 
    } 
} 
0
private Stream ReadWhenAvailable(FileInfo finfo, TimeSpan? ts = null) => Task.Run(() => 
    { 
     ts = ts == null ? new TimeSpan(long.MaxValue) : ts; 
     var start = DateTime.Now; 
     while (DateTime.Now - start < ts) 
     { 
      Thread.Sleep(200); 
      try 
      { 
       return new FileStream(finfo.FullName, FileMode.Open); 
      } 
      catch { } 
     } 
     return null; 
    }) 
    .Result; 

、あなたはあなたに合わせて、このの側面を変更することができますニーズ。

関連する問題