2012-02-20 13 views
13

ファイルを削除した後、ファイルリストを更新する際に問題がありました。ファイルを削除するコマンドを与えたとき、リフレッシュメソッドが削除されるはずのファイルにアクセスしようとしたため、例外がスローされました。システムがファイルを削除するのを待っています

いくつかの考えとデバッグの後、私は、システムがファイルを削除するのに時間が必要であるという事実に結論づけました。そして、私はこれを次のように解決します:

//Deleting file 
System.Threading.Thread.Sleep(2000); 
//Refreshing list 

それはうまくいきました。

私の質問は

ファイルを削除してからコードを続行ないシステムを待つよりエレガントな方法はありますが...?

+1

たちは、コードの残りの部分を見ることはできますか?また、どのような種類のファイルシステム(ローカルNTFSまたは何らかの形式のNFS)がありますか?とにかく、NTFS上のほとんどのファイルシステムの削除操作はアトミックです。 –

+0

これはNTFS上です。興味のあるコードの部分。Deleteメソッドは、ディレクトリ内のすべてのファイルとディレクトリ自体を再帰的に削除します。私はそれが関係しているとは思わなかったので、私はファイルを削除する必要があると言った...それは同じものですね。 – kr85

+1

全くありません。私は答えを残します –

答えて

5

私が考えることができる最もエレガントな方法は、FileSystemWatcherを使用し、そのDeletedイベントを購読しています。

+3

これはNFSパーティション上にあると思われますが、FileSystemWatcherはそうではないかもしれません信頼できる:http://stackoverflow.com/questions/239988/filesystemwatcher-vs-polling-to-watch-for-changes –

+1

@ChrisShain私はこれをNTFSシステムで使用しただけであり、うまく動作します。 NFSについてはよく分かりません – GETah

+0

あまりにも複雑な解決策だと思います。 – Beatles1692

1

NTFS上のDirectory.Delete、特にthe overload that takes a 'recursive' booleanを使用してディレクトリを削除することは、プログラムの観点からアトミックな操作にする必要があります。自分で手動で再発する必要はありません。

+0

それはそうすべきですが、そうではありません。 Directory.Existsは、特に次の行である場合にtrueを返すことがあります。さらに悪いことに、Directory.Createは、Directory.Deleteの後すぐに呼び出されたときに投げられることがあります。 – ILMTitan

0

Directory.Deleteは、最初に検出されたエラーで例外をスローします。できるだけ多くのファイルとサブディレクトリを削除したい場合は、Directory.Deleteを使用しないでください。また、ループ内にtry/catchブロックを持つ独自の再帰的な削除を作成する必要があります。たとえば、一時ファイルをクリーンアップしようとしていて、ファイルの1つがロックされているとします。

1

ここにFileWatcherを使用しているコードがあります。私たちが行うことができるようにしたいことは

await Utils.DeleteDirectoryAsync("c:\temp\foo", recurse: true); 

ある以下

using System; 
using System.IO; 
using System.Reactive; 
using System.Reactive.Linq; 
using System.Reactive.Subjects; 
using System.Threading.Tasks; 

namespace Utils 
{ 
    internal class FileWatcher : IDisposable 
    { 
     readonly FileSystemWatcher _Watcher; 

     public Subject<FileSystemEventArgs> Changed = new Subject<FileSystemEventArgs>(); 

     public FileWatcher(string file) 
     { 
      // Create a new FileSystemWatcher and set its properties. 
      _Watcher = new FileSystemWatcher 
         { 
          Path = Path.GetDirectoryName(file), 
          NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite 
              | NotifyFilters.FileName | NotifyFilters.DirectoryName, 
          Filter =Path.GetFileName(file) 
         }; 

      // Add event handlers. 
      _Watcher.Changed += OnChanged; 
      _Watcher.Created += OnChanged; 
      _Watcher.Deleted += OnChanged; 
      _Watcher.Renamed += OnChanged; 

      // Begin watching. 
      _Watcher.EnableRaisingEvents = true; 
     } 

     // Define the event handlers. 
     private void OnChanged(object source, FileSystemEventArgs e) 
     { 
      Changed.OnNext(e); 
     } 


     public void Dispose() 
     { 
      _Watcher.Dispose(); 
     } 
    } 
} 

と上記観測可能を活用するいくつかのutilsのそれを実装しています。

public static class FileUtils 
{ 
    public static IObservable<FileSystemEventArgs> ChangedObservable(string path) 
    { 
     if (path == null) 
      return Observable.Never<FileSystemEventArgs>(); 

     return Observable.Using(() => new FileWatcher(path), watcher => watcher.Changed); 
    } 

    public static Task DeleteDirectoryAsync(string path, bool recurse) 
    { 
     var task = new TaskCompletionSource<Unit>(); 

     if (Directory.Exists(path)) 
     { 
      ChangedObservable(path) 
       .Where(f => f.ChangeType == WatcherChangeTypes.Deleted) 
       .Take(1) 
       .Subscribe(v => task.SetResult(Unit.Default)); 

      Directory.Delete(path, recurse); 
     } 
     else 
     { 
      task.SetResult(Unit.Default); 
     } 

     return task.Task; 
    } 
} 
9

これが私の作品:

public static void DeleteFile(String fileToDelete) 
{ 
    var fi = new System.IO.FileInfo(fileToDelete); 
    if (fi.Exists) 
    { 
     fi.Delete(); 
     fi.Refresh(); 
     while (fi.Exists) 
     { System.Threading.Thread.Sleep(100); 
      fi.Refresh(); 
     } 
    } 
} 

私はほとんどの時間は、whileループが入力されないことがわかります。

2

軽量コードFileSystemWatcherを使用するには、そのDeletedイベントを購読して待ちます。

void DeleteFileAndWait(string filepath, int timeout = 30000) 
{ 
    using (var fw = new FileSystemWatcher(Path.GetDirectoryName(filepath), Path.GetFileName(filepath))) 
    using (var mre = new ManualResetEventSlim()) 
    { 
     fw.EnableRaisingEvents = true; 
     fw.Deleted += (object sender, FileSystemEventArgs e) => 
     { 
      mre.Set(); 
     }; 
     File.Delete(filepath); 
     mre.Wait(timeout); 
    } 
} 
0

私はいつもこの使用:

System.GC.Collect(); 
System.GC.WaitForPendingFinalizers(); 

herehere

関連する問題