刪除文件後,我在刷新文件列表時遇到問題。當我發出刪除文件的命令時,由於刷新方法試圖訪問應該刪除的文件,所以拋出了異常。等待系統刪除文件
經過一番思考和調試後,我得出結論,問題在於系統需要一些時間來刪除文件。我解決這個問題:
//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