2012-02-20 95 views
13

刪除文件後,我在刷新文件列表時遇到問題。當我發出刪除文件的命令時,由於刷新方法試圖訪問應該刪除的文件,所以拋出了異常。等待系統刪除文件

經過一番思考和調試後,我得出結論,問題在於系統需要一些時間來刪除文件。我解決這個問題:

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

它工作正常。

我的問題是

有沒有更優雅的方式來等待系統就刪除文件,然後繼續代碼...?

+1

我們可以看到代碼的休息嗎?另外,什麼樣的文件系統(本地NTFS或某種形式的NFS)?無論如何,NTFS上的大多數文件系統刪除操作都是原子操作。 – 2012-02-20 23:31:36

+0

它在NTFS上。你感興趣的代碼部分是什麼。刪除方法遞歸地刪除目錄中的所有文件和目錄本身。我沒有想到這是相關的,所以我說我需要刪除一個文件......這是同樣的事情,不是嗎? – kr85 2012-02-20 23:43:06

+1

沒有。我會留下一個答案 – 2012-02-20 23:44:01

回答

5

我能想到的最優雅的方式是使用FileSystemWatcher並訂閱其Deleted事件。

+3

如果這是在NFS分區上,正如我猜想的那樣,那麼FileSystemWatcher可能不會可靠:http://stackoverflow.com/questions/239988/filesystemwatcher-vs-polling-to-watch-for-changes – 2012-02-20 23:40:34

+1

@ChrisShain我只在NTFS系統上使用它,它的工作原理非常棒。不知道關於NFS雖然 – GETah 2012-02-20 23:44:04

+0

我認爲太複雜的解決方案 – Beatles1692 2012-02-20 23:49:42

1

在NTFS上使用Directory.Delete,特別是the overload that takes a 'recursive' boolean刪除目錄應該是從程序角度來看的原子操作。無需手動遞歸自己。

+0

它應該是,但事實並非如此。 Directory.Exists有時會返回true,尤其是當它是下一行時。更糟糕的是,Directory.Create有時會在Directory.Delete後快速調用。 – ILMTitan 2017-07-18 00:29:27

0

Directory.Delete將在遇到的第一個錯誤時拋出異常。如果你想繼續刪除儘可能多的文件和子目錄,那麼你不應該使用Directory.Delete,並且應該在循環內用try/catch塊編寫你自己的遞歸刪除。當你想要這樣做的一個例子是,如果你正在嘗試清理臨時文件,並且其中一個文件已被鎖定。

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