1

I have a pet project I'm working on where the FileSystemWatcher is vexing me.

Here's the initialization code:

for (var xx = 0; xx < _roots.Count; xx++)
{
    var watcher = new FileSystemWatcher();
    var root = _roots[xx];

    watcher.Path = root;
    // watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName;
    watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName;

    watcher.Filter = "*.*";
    watcher.Changed += new FileSystemEventHandler(OnChanged);
    watcher.Created += new FileSystemEventHandler(OnChanged);
    watcher.Deleted += new FileSystemEventHandler(OnChanged);
    watcher.Renamed += new RenamedEventHandler(OnRenamed);

    watcher.EnableRaisingEvents = true;

    _rootWatchers.Add(watcher);
}

Let's say the root we're watching "c:\root" and there's a sub directory "c:\root\subdir" that contains a file called "file1.txt".

The watcher is up and running and I delete "file1.txt". When the handler is called and examine the values of FileSystemEventArgs.

I expect for e.Name == "file1.txt" and e.FullPath == "c:\\root\\subdir\\file1.txt.

The actual values are "subdir" and "c:\\root\\subdir".

I'm sure it's something simple I missed in the documentation somewhere.

Daniel A. White
  • 187,200
  • 47
  • 362
  • 445
amber
  • 1,067
  • 3
  • 22
  • 42
  • I think this might help: https://stackoverflow.com/questions/11255360/how-do-you-get-the-name-of-a-new-file-created-using-filesystemwatcher – Amr Elgarhy Jan 11 '18 at 18:53
  • That was one of the first questions I read on the FileSystemWatcher before asking my question. It doesn't help as it covers using the instance properties of `Name` and `FullName` to get the information. This question is about the event returning the directory information rather than the file information. – amber Jan 11 '18 at 19:09
  • Just an idea I would try if I was near a keyboard right now: set up a test with just the deletion monitoring for one path. If the file details are as expected, add in the rest of your complexity to see if anything else on the code sample is causing an issue. Every article I’ve seen about file watcher indicates the file path should be reported (as a relative path I think). Maybe you mapping several event handlers to the same method is muddying your water. Just a guess. I’d run some tests but I’m on my phone atm – J M Jan 11 '18 at 19:14

1 Answers1

4

You are correct, the issue you are facing is practically one of forgetting to set a property.

If you set watcher.IncludeSubdirectories = true;, you'll get notified about the file deletion even in deeper levels.

In the default mode, the FileSystemWatcher only records changes to the given directory. Sub-directories being modeled sort of directory entries similar to files, any additions/deletions inside them are just reported as changes directly to the sub-directories (you would see that if you checked the FileSystemEventArgs.ChangeType property in the OnChanged handler).

Even if you turn on sub-directories monitoring, you'll still get a change event (FileSystemEventArgs.ChangeType = WatcherChangeTypes.Changed) for the subdir directory as it is also modified when you delete a file inside it. That is in addition to the deletion event for the file.

My test code:

static void Main(string[] args)
{
    var watcher = new FileSystemWatcher();

    watcher.Path = @"C:\test_dir";
    // watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName;
    watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName;

    watcher.Filter = "*.*";
    watcher.Changed += new FileSystemEventHandler(OnChanged);
    watcher.Created += new FileSystemEventHandler(OnChanged);
    watcher.Deleted += new FileSystemEventHandler(OnChanged);
    watcher.Renamed += new RenamedEventHandler(OnRenamed);

    watcher.IncludeSubdirectories = true;

    watcher.EnableRaisingEvents = true;

    while (true)
    {
    }
}

private static void OnRenamed(object sender, RenamedEventArgs e)
{
    Console.WriteLine($"OnRenamed: {e.FullPath}, {e.OldFullPath}");
}

private static void OnChanged(object sender, FileSystemEventArgs e)
{
    Console.WriteLine($"OnChanged: {e.ChangeType}, {e.Name}[{e.FullPath}]");
}
Zdeněk Jelínek
  • 2,611
  • 1
  • 17
  • 23
  • My test above has the IncludeSubdirectories set to true and I still get the missing file path on the OnDeleted event if the OnChanged event is wired up. – J M Jan 11 '18 at 20:50
  • @JM Could you please be more specific about your OS and .NET version? It works for me with Win10 and .NET Framework 4.7.1. I have included code I use. – Zdeněk Jelínek Jan 11 '18 at 20:53
  • My OS and .NET version are also Win 10 and .NET 4.7.1. I will run again to double check mine to be 100% sure. I will run yours too and compare. – J M Jan 11 '18 at 20:54
  • @JM Your code works for me as well. Output: Watcher_Deleted C:\Temp\Root\subdir\test_file.txt Watcher_Changed C:\Temp\Root\subdir. – Zdeněk Jelínek Jan 11 '18 at 20:57
  • When I run yours I get: OnChanged: Created, subdir\New Text Document.txt[C:\test_dir\subdir\New Text Document.txt] OnChanged: Changed, subdir\New Text Document.txt[C:\test_dir\subdir\New Text Document.txt] OnChanged: Changed, subdir[C:\test_dir\subdir] OnChanged: Deleted, subdir\New Text Document.txt[C:\test_dir\subdir\New Text Document.txt] OnChanged: Changed, subdir[C:\test_dir\subdir]. That was for the creation of a text file followed by the deletion of the file. – J M Jan 11 '18 at 21:01
  • And when I comment out the wiring up of your OnChanged event, I get the full path again. – J M Jan 11 '18 at 21:04
  • Yes, that is because there are two event invocations when you delete the file: 1. the file deletion gets reported ("OnChanged: Deleted, subdir\New Text Document.txt[C:\test_dir\subdir\New Text Document.txt]" -- notice: full file path to deleted file); 2. the subdirectory of watched directory modification gets reported ("OnChanged: Changed, subdir[C:\test_dir\subdir]" -- notice: only directory path). That is all as expected. What is probably misleading to you is the fact that the `OnChanged` method group is registered to all of the events. – Zdeněk Jelínek Jan 11 '18 at 21:07
  • Right, I see now. Thanks for explaining :). – J M Jan 11 '18 at 21:09
  • @JM glad we could clean that one up. I extended the answer a bit to hopefully make it clearer :) Happy coding! – Zdeněk Jelínek Jan 11 '18 at 21:10