Help with the FileSystemWatcher Object in .NET

Hi Experts,

I am getting some odd behaviour with the FileSystemWatcher object. Please refer to my code snippets below:
Whenever I create a new XML file in the specified directory the file name get printed twice as opposed to a single time. Tried setting a breakpoint in my eventhandler and it looks like the function is getting called twice which doesnt explain things.

 What I am trying to achieve is to read the contents of the newly created and then delete it. So if the function get called twice,it will through up a filenotfound exception the second time. Came across this oddy while testing. What am I missing in here.

static void Main(string[] args)
        {
 
            FileSystemWatcher watcher = new FileSystemWatcher();
            watcher.Path = @"C:\XmlFiles";
            watcher.Filter = "*.xml";
            watcher.Created += new FileSystemEventHandler(FileCreated);
            watcher.EnableRaisingEvents = true;
            Console.WriteLine("Started...");
            Console.ReadLine();
        }
 
        static void FileCreated(object sender, FileSystemEventArgs e)
        {
           Console.WriteLine(e.FullPath);
         }

Open in new window

AxonitesAsked:
Who is Participating?
 
anyoneisConnect With a Mentor Commented:
I have gathered from google that this matter of duplicate events is due to antivirus software. But, it's our job to get around it. There are several scenarios that you have to deal with - and various programs will handle each scenario differently. For example, one program might delete an existing file then recreate it. Another might truncate it and write it....

Here is what I do, it seems to work well:
When a file changes, I start a timer for that file. I keep track of the file and the timer in a hash table.

When the timer expires, I lock the hash table and find the timer. Then, I try to open the file. If I get it, I assume that the changes to the file are done and I process the file. Otherwise I reset the timer for another time period (I use 5 seconds - way more than I probably need to.)

This seems to reliably capture files that are dropped in, and files that are created and expanded within my watched directory.

There are a bunch of details. For example, it is possible that you would get a create, then a tijmer expiration, then another create before the file available status happens. Your time window must be small enough to make this eventuality unlikely, if you must capture each instance of the changed file.

David
0
 
abelCommented:
Interesting. I just copied your code into a winforms application and I can't replicate your behavior. How are you trying to create the file? Can you try to select the file in an Explorer window an hit Ctrl-C / Ctrl-V and check if that also creates two events?

What version of .NET are you on?
0
 
AxonitesAuthor Commented:
Hi Abel,

I am running dotnet 3.5, got my xml file opened in an editor. when I save it onto C:\XmlFiles using different file names the created event triggers and calls the FileCreated method which is my event handler for the same.

Now Interestingly when I try the Ctrl-C/Ctrl-V sequence the event handler gets called only once.
0
Cloud Class® Course: Microsoft Azure 2017

Azure has a changed a lot since it was originally introduce by adding new services and features. Do you know everything you need to about Azure? This course will teach you about the Azure App Service, monitoring and application insights, DevOps, and Team Services.

 
anyoneisCommented:
Oh, to answer your present question, in the first create event, you will find that FileInfo(e.FullPathName).Exists is false. But it is true on the second call.

David
0
 
anyoneisCommented:
Here is a console program based on yours that will help illustrate the issues.

If I re-save a pre-exsting file XMLFile2.xml then create a new one XMLFile4.xml, I get:

Started...
File Changed Event
        C:\XmlFiles\XMLFile2.xml
        Exists and is 56 bytes
File Changed Event
        C:\XmlFiles\XMLFile2.xml
        Exists and is 56 bytes
File Created Event
        C:\XmlFiles\XMLFile4.xml
        Does not exist
File Deleted Event
        C:\XmlFiles\XMLFile4.xml
        Does not exist
File Created Event
        C:\XmlFiles\XMLFile4.xml
        Exists and is 56 bytes
File Changed Event
        C:\XmlFiles\XMLFile4.xml
        Exists and is 56 bytes
File Changed Event
        C:\XmlFiles\XMLFile4.xml
        Exists and is 56 bytes




using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
 
namespace FileSystemWatcherTest
{
    class Program
    {
        
        static void Main(string[] args)
        {
            FileSystemWatcher watcher = new FileSystemWatcher();
            watcher.Path = @"C:\XmlFiles";
            watcher.Filter = "*.xml";
            watcher.Created += new FileSystemEventHandler(FileCreated);
            watcher.Deleted += new FileSystemEventHandler(FileDeleted);
            watcher.Changed += new FileSystemEventHandler(FileChanged);
            watcher.Renamed += new RenamedEventHandler(FileRenamed);
            watcher.EnableRaisingEvents = true;
            Console.WriteLine("Started...");
            Console.ReadLine();
        }
 
        static void DisplayStuff(object sender, FileSystemEventArgs e)
        {
            Console.WriteLine("File {0} Event", e.ChangeType);
            Console.WriteLine("\t{0}", e.FullPath);
 
            FileInfo fInfo = new FileInfo(e.FullPath);
            if (fInfo.Exists)
                Console.WriteLine("\tExists and is {0} bytes", fInfo.Length);
            else
                Console.WriteLine("\tDoes not exist");
        }
 
        static void DisplayRenameStuff(object sender, RenamedEventArgs e)
        {
            Console.WriteLine("File {0} Event", e.ChangeType);
            Console.WriteLine("\tNew Name: {0}", e.FullPath);
            Console.WriteLine("\tOld Name: {0}", e.OldFullPath);
 
            FileInfo fInfo = new FileInfo(e.FullPath);
            if (fInfo.Exists)
                Console.WriteLine("\tExists and is {0} bytes", fInfo.Length);
            else
                Console.WriteLine("\tDoes not exist");
        }
 
        static void FileCreated(object sender, FileSystemEventArgs e)
        {
            DisplayStuff(sender, e);
        }
 
        static void FileDeleted(object sender, FileSystemEventArgs e)
        {
            DisplayStuff(sender, e);
        }
        static void FileChanged(object sender, FileSystemEventArgs e)
        {
            DisplayStuff(sender, e);
        }
        static void FileRenamed(object sender, RenamedEventArgs e)
        {
            DisplayRenameStuff(sender, e);
        }
    }
}

Open in new window

0
 
AxonitesAuthor Commented:
Hi anyoneis,

Really appreciate your time in providing a detailed example.
Can you explain to me whats happening in one of your test cases as below:

File Created Event
        C:\XmlFiles\XMLFile4.xml
        Does not exist

I came across a similar situation, when I tried to open the file created, from  my create event handler a file not found exception was thrown.
Any reason for this behavior?
0
 
abelConnect With a Mentor Commented:
> Now Interestingly when I try the Ctrl-C/Ctrl-V sequence the event handler gets called only once.

that looks promising. Probably (not sure) the first time the XML file is "touched", which is to make sure it can be created (similar to hitting rightmouseclick in Explorer and then "New Text File", first a file is created, then the rename). It might very well be that the first Created event would be about a file not containing anything. As anyoneis has said, this might also be due to the presence of a virus scanner.

Now, if you do need to react to these double events as created by this program, and you need to act on them, I would wait a while for the second event to happen. If it doesn't happen, you process and remove the file. If it does happen, you do the same.

What I mean with "wait for the same event to happen" you can do as follows (needs some tweaking, but you'll get my drift):

private void FileCreated(object sender, FileSystemEventArgs e)
{
    watcher.EnableRaisingEvents = false;
    WaitForChangedResult result;
    result = watcher.WaitForChanged(WatcherChangeTypes.Created, 1000);
    if (!result.TimedOut)
        Console.WriteLine(e.FullPath + " has been twice created");
    else
        Console.WriteLine(e.FullPath + " has been created");
 
    watcher.EnableRaisingEvents = true;
}

Open in new window

0
 
anyoneisCommented:
I don't know what the reason is for the non-existent file on the created event, but I do know that it gives you a way to distinguish between the two events.

David
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.