2012-02-20 97 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