[c#] FileSystemWatcher Changed event is raised twice

The solution really depends on the use case. Are you watching out for new files that don't change, or one file that changes every once in a while, of changes very often? In my case, it changes not too often, and I don't want to miss any of these changes.

But I also do not want the change event where the writing process is not yet done writing.

In my case, I noticed 6 (six!!) onchange events on writing a 125 char txt file.

My solution is a mix of polling, that is often looked negatively at, and the change-event. Normal polling is slow, say every 10 seconds, just in case the FileSystemWatcher (FSW) "misses" an event. The polling responds immediately to a FSW change event.

The trick is that at a FSW.Change event, the polling goes faster, say every 100 ms, and waits until the file is stable. So we have "two phased polling": phase 1 is slow, but responds immediately on a FSW file change event. Phase 2 is fast, waiting for a stable file.

If the FSW detects multiple file changes, each of those events speeds up the polling loop, and will effectively start a new, short, waiting cycle. Only after the polling loop detects no further change in file last write time, it assumes that the file is stable, and your code may handle the changed file.

I chose timeouts of 10 seconds and 100 ms, but your use case may need different timeout values.

Here is the polling, where AppConfig.fiIO is the FileInfo to watch for:

private readonly EventWaitHandle ewhTimeout = new AutoResetEvent(false);

private void TwoPhasedPolling()
{
    bool WaitForChange = true; //false: wait until stable
    DateTime LastWriteTime = DateTime.MinValue;
    while (true)
    {
        // wait for next poll (timeout), or FSW event
        bool GotOne = ewhTimeout.WaitOne(WaitForChange ? 10 * 1000 : 100);
        if (GotOne)
        {
            // WaitOne interrupted: end of Phase1: FSW detected file change
            WaitForChange = false;
        }
        else
        {
            // WaitOne timed out: Phase2: check file write time for change
            if (AppConfig.fiIO.LastWriteTime > LastWriteTime)
            {
                LastWriteTime = AppConfig.fiIO.LastWriteTime;
            }
            else
            {
                // End of Phase2: file has changed and is stable
                WaitForChange = true;
                // action on changed file
                ... your code here ...
            }}}}

private void fileSystemWatcher1_Changed(object sender, FileSystemEventArgs e)
{
    ewhTimeout.Set();
}

NB: yes, I don't like }}}} either, but it makes the listing shorter so that you don't have to scroll :-)