How can I watch a directory with a FileSystemWatcher and still allow for it to be properly deleted?
Consider this code:
string dir = Environment.CurrentDirectory + @"\a";
Directory.CreateDirectory(dir);
FileSystemWatcher watcher = new FileSystemWatcher(dir);
watcher.IncludeSubdirectories = false;
wa开发者_C百科tcher.EnableRaisingEvents = true;
Console.WriteLine("Deleting " + dir);
Directory.Delete(dir, true);
if (Directory.Exists(dir))
{
Console.WriteLine("Getting dirs of " + dir);
Directory.GetDirectories(dir);
}
Console.ReadLine();
Interestingly this throws an UnauthorizedAccessException on Directory.GetDirectories(dir)
.
Deleting the watched directory returns without error, but Directory.Exists() still returns true and the directory is still listed. Furthermore accessing the directory yields "Access denied" for any program. Once the .NET application with the FileSystemWatcher exits the directory vanishes.
How can I watch a directory while still allowing it to be properly deleted?
You did in fact delete the directory. But the directory won't be physically removed from the file system until the last handle that references it is closed. Any attempt to open it in between (like you did with GetDirectories) will fail with an access denied error.
The same mechanism exists for files. Review FileShare.Delete
Try this line:
if (new DirectoryInfo(dir).Exists)
instead of:
if (Directory.Exists(dir))
You should use FileSystemInfo.Refresh. After .Refresh() .Exists shows correct result:
var dir = new DirectoryInfo(path);
// delete dir in explorer
System.Diagnostics.Debug.Assert(dir.Exists); // true
dir.Refresh();
System.Diagnostics.Debug.Assert(!dir.Exists); // false
Unfortunately FileSystemWatcher has taken a handle to the directory this means that when the directory is deleted that there is still a handle to the directory marked as PENDING DELETE. I've tried some experiments and it seems that you can use the Error event handler from FileSystemWatcher to identify when this happens.
public myClass(String dir)
{
mDir = dir;
Directory.CreateDirectory(mDir);
InitFileSystemWatcher();
Console.WriteLine("Deleting " + mDir);
Directory.Delete(mDir, true);
}
private FileSystemWatcher watcher;
private string mDir;
private void MyErrorHandler(object sender, FileSystemEventArgs args)
{
// You can try to recreate the FileSystemWatcher here
try
{
mWatcher.Error -= MyErrorHandler;
mWatcher.Dispose();
InitFileSystemWatcher();
}
catch (Exception)
{
// a bit nasty catching Exception, but you can't do much
// but the handle should be released now
}
// you might not be able to check immediately as your old FileSystemWatcher
// is in your current callstack, but it's a start.
}
private void InitFileSystemWatcher()
{
mWatcher = new FileSystemWatcher(mDir);
mWatcher.IncludeSubdirectories = false;
mWatcher.EnableRaisingEvents = true;
mWatcher.Error += MyErrorHandler;
}
精彩评论