FileSystemWatcher events raising twice despite taking measures against it
Asked Answered
B

2

5

I've browsed quite a few threads on here and on other sites for solutions to this problem.

Here's my FileMonitor class:

class FileMonitor
{
    public FileMonitor(String path)
    {
        try
        {
            var watcher = new FileSystemWatcher()
            {
                Path = path,
                IncludeSubdirectories = true,
                InternalBufferSize = 65536,
                EnableRaisingEvents = true
            };

            watcher.Changed += new FileSystemEventHandler(OnFileChanged);
            watcher.Created += new FileSystemEventHandler(OnFileCreated);
            watcher.Deleted += new FileSystemEventHandler(OnFileDeleted);
            watcher.Renamed += new RenamedEventHandler(OnFileRenamed);
            watcher.Error += new ErrorEventHandler(OnWatcherError);
        }
        catch (Exception)
        {

            throw;
        }
    }

    private void OnWatcherError(object sender, ErrorEventArgs e)
    {

    }

    private void OnFileChanged(object sender, FileSystemEventArgs e)
    {
        try
        {
            ((FileSystemWatcher)sender).EnableRaisingEvents = false;

            LogFileSystemChanges(e);
        }

        finally
        {
            ((FileSystemWatcher)sender).EnableRaisingEvents = true;
        }
    }

    private void OnFileCreated(object sender, FileSystemEventArgs e)
    {
        try
        {
            ((FileSystemWatcher)sender).EnableRaisingEvents = false;

            LogFileSystemChanges(e);
        }

        finally
        {
            ((FileSystemWatcher)sender).EnableRaisingEvents = true;
        }
    }

    private void OnFileDeleted(object sender, FileSystemEventArgs e)
    {
        try
        {
            ((FileSystemWatcher)sender).EnableRaisingEvents = false;

            LogFileSystemChanges(e);
        }

        finally
        {
            ((FileSystemWatcher)sender).EnableRaisingEvents = true;
        }
    }

    private void OnFileRenamed(object sender, RenamedEventArgs e)
    {
        try
        {
            ((FileSystemWatcher)sender).EnableRaisingEvents = false;

            LogFileSystemRenaming(e);
        }

        finally
        {
            ((FileSystemWatcher)sender).EnableRaisingEvents = true;
        }
    }

    private void LogFileSystemChanges(FileSystemEventArgs e)
    {
        string log = string.Format("{0:G}: {1} | {2}", DateTime.Now, e.FullPath, e.ChangeType);
        Console.WriteLine(log);
    }

    private void LogFileSystemRenaming(RenamedEventArgs e)
    {
        string log = string.Format("{0:G}: {1} | Old name: {2}", DateTime.Now, e.FullPath, e.OldName);
        Console.WriteLine(log);
    }
}

As you can tell, I have tried the "lock" of ((FileSystemWatcher)sender).EnableRaisingEvents = false;, but I can tell from my console output my events are triggering twice.

Any ideas on this? I'm really not sure where to go from here.

Bedspread answered 31/3, 2014 at 16:45 Comment(2)
Three weeks have passed but you still didn't follow-up. Did you solve the problem? Can you vote an answer, please, or tell us how you solved it? Thanks!Reichsmark
Sorry, I haven't found a solution. I kind-of gave up upon realizing how many problems many people have had with the FileSystemWatcher.Bedspread
R
6

I've had the same problem and after much ado came to the conclusion that Notepad writes a file three times (!) in row. If an app really saves that much often (maybe to triangulate backups and such) there isn't much you can do.

I also noticed you have attached to all events, you should narrow it down to the least you need and filter out those you aren't interested in with the NotifyFilters.

Reichsmark answered 31/3, 2014 at 16:59 Comment(4)
Perhaps a new file is written with a new name, the old file is deleted and then the new file is renamed to the old file name? Would this raise 3 write events?Hume
Yes, it is also possible that the *.txt file is renamed to *.bak, a new *.txt file is created and then the backup is deleted. This would also raise 3 events on the folder. Substitute the txt/bak extensions with whatever you use. It totally depends on the program that is used.Reichsmark
I think that approach is used in MFC at least - disk events are plentiful and difficult to deal with.Hume
Maybe someone should start a github project implementing a wrapper leveraging this leaky abstraction and adding best practices control code to make it work in a more useful way, with higher level events, timeouts, fallback on polling and whatnot... those typical workarounds you often see on Linux.Reichsmark
H
5

I've tried to use the FileSystemWatcher class before (many years ago it turns out - 2008), and experienced major problems. It is a leaky abstraction at best. I reported my findings back then on CodeProject. Look for "Glytzhkof" in the comments list. As I recall I had problems with just about every aspect of the class, but it might have been improved now after so many years.

In summary my experience back in the day was that events disappeared altogether or piled up causing exceptions based on variables such as whether a disk's write cache was enabled, whether RAID, NAS or regular disks were accessed, and other random hardware issues that I do not recall exactly. Interestingly it seems it worked with UNC paths. No idea why. Mapped drives failed.

Have a look at the summary in the Code Project discussion. I am sure there are improvements since I tried it out, and a few new bugs perhaps :-). It seems disk storage hardware is hard to deal with as a high level abstraction - it leaks. Personally I ended up scanning for files manually using a service and regular disk functions. I wasted a lot of time before doing things manually.

UPDATE: See new info here: https://mcmap.net/q/104659/-why-are-filesystemwatcher-attribute-changes-detected-on-windows-7-but-not-windows-8

Heartbreak answered 31/3, 2014 at 17:48 Comment(3)
+1 on all you say, I've had the same experience with this. Furthermore, it seems to depend on the format, too. UNC on NTFS works but an UNC to a non-NTFS drive or even worse non-Windows... doesn't work more than it does. I understand that without any support on the controller/driver/format side it's impossible to implement, so to make this work a total hardware/driver/protocol support is needed across platforms. That's not something you can suppose to have easily. Still, I use it when I need it. It's very useful until... it stops working :)Reichsmark
I've taken a look at your CodeProject! I'd +1 you again if I could :) Excellent work! That's what I meant with my previous comment.Reichsmark
regular polling will have the very undesirable side effect of re-spinning up the disks. espcially in laptop-mode. or, preventing spin down altogether because of the timer being shorter than spin down delay. This is just wrong™Glosseme

© 2022 - 2024 — McMap. All rights reserved.