删除文件后,我在刷新文件列表时遇到问题。当我发出删除文件的命令时,由于刷新方法试图访问应该删除的文件,所以抛出了异常。等待系统删除文件
经过一番思考和调试后,我得出结论,问题在于系统需要一些时间来删除文件。我解决这个问题:
//Deleting file
System.Threading.Thread.Sleep(2000);
//Refreshing list
它工作正常。
我的问题是
有没有更优雅的方式来等待系统就删除文件,然后继续代码...?
删除文件后,我在刷新文件列表时遇到问题。当我发出删除文件的命令时,由于刷新方法试图访问应该删除的文件,所以抛出了异常。等待系统删除文件
经过一番思考和调试后,我得出结论,问题在于系统需要一些时间来删除文件。我解决这个问题:
//Deleting file
System.Threading.Thread.Sleep(2000);
//Refreshing list
它工作正常。
我的问题是
有没有更优雅的方式来等待系统就删除文件,然后继续代码...?
我能想到的最优雅的方式是使用FileSystemWatcher并订阅其Deleted
事件。
如果这是在NFS分区上,正如我猜想的那样,那么FileSystemWatcher可能不会可靠:http://stackoverflow.com/questions/239988/filesystemwatcher-vs-polling-to-watch-for-changes – 2012-02-20 23:40:34
@ChrisShain我只在NTFS系统上使用它,它的工作原理非常棒。不知道关于NFS虽然 – GETah 2012-02-20 23:44:04
我认为太复杂的解决方案 – Beatles1692 2012-02-20 23:49:42
在NTFS上使用Directory.Delete,特别是the overload that takes a 'recursive' boolean删除目录应该是从程序角度来看的原子操作。无需手动递归自己。
它应该是,但事实并非如此。 Directory.Exists有时会返回true,尤其是当它是下一行时。更糟糕的是,Directory.Create有时会在Directory.Delete后快速调用。 – ILMTitan 2017-07-18 00:29:27
Directory.Delete将在遇到的第一个错误时抛出异常。如果你想继续删除尽可能多的文件和子目录,那么你不应该使用Directory.Delete,并且应该在循环内用try/catch块编写你自己的递归删除。当你想要这样做的一个例子是,如果你正在尝试清理临时文件,并且其中一个文件已被锁定。
这是一些使用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;
}
}
这个工作对我来说:
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循环将不被输入。
轻量级代码使用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);
}
}
我们可以看到代码的休息吗?另外,什么样的文件系统(本地NTFS或某种形式的NFS)?无论如何,NTFS上的大多数文件系统删除操作都是原子操作。 – 2012-02-20 23:31:36
它在NTFS上。你感兴趣的代码部分是什么。删除方法递归地删除目录中的所有文件和目录本身。我没有想到这是相关的,所以我说我需要删除一个文件......这是同样的事情,不是吗? – kr85 2012-02-20 23:43:06
没有。我会留下一个答案 – 2012-02-20 23:44:01