Click here to Skip to main content
15,893,508 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
There is a process we are running, which creates files and writes data on a particular event. File is created in folder: C:\\EventListenerFolder\\ . Now whenever a new file is created and data is written to the file, we need to send a mail.


public static void RunEventListenerPrgm()
{
//the mail notification has to go as a file gets generated in C:\\EventListenerFolder\\
while (true)
{
System.IO.FileSystemWatcher m_Watcher = new System.IO.FileSystemWatcher();
m_Watcher.Filter = "*.txt";
m_Watcher.Path = "C:\\EventListenerFolder\\";
m_Watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName;
m_Watcher.Changed += new FileSystemEventHandler(OnChanged);
m_Watcher.EnableRaisingEvents = true;
}
}

public static void OnChanged(object sender, FileSystemEventArgs e)
{
string stringReceived;
string[] allFiles = System.IO.Directory.GetFiles("C:\\EventListenerFolder\\");
foreach (string file in allFiles)
{
Console.WriteLine("EventListener Match File Found. FILE NAME : " + file);
try
{
stringReceived = System.IO.File.ReadAllText(file);
}
catch (Exception ex)
{
continue; // to avoid reading of file when it is in process of being written . hence we wait till the file is written and then we read it
}
SendMailFunction(stringReceived);
File.Delete(file);

}
}

In this scenario, we are getting 100+ mail for the same file. And we want only one mail for one file to be sent.

What I have tried:

Tried changing m_Watcher.Changed += new FileSystemEventHandler(OnChanged);
to m_Watcher.Created+= new FileSystemEventHandler(OnChanged);
still doesnot work.

Could it be that the file watcher event Filter I am using is incorrect?
Could you please help me on the same?
Posted
Updated 21-Sep-17 7:07am

1 solution

So many problems; where to begin? :)

Your OnChanged event handler is ignoring the information about which file changed, and sending a notification for all files in the folder. You should use e.FullName to process just the file which has changed:
C#
private static void OnChanged(object sender, FileSystemEventArgs e)
{
    string file = e.FullName;
    Console.WriteLine("EventListener Match File Found. FILE NAME : {0}", file);
    
    try
    {
        string stringReceived = File.ReadAllText(file);
        SendMailFunction(stringReceived);
        File.Delete(file);
    }
    catch (IOException)
    {
    }
}

Your RunEventListenerPrgm method is creating multiple new FileSystemWatcher instances in a tight loop. Every single instance you create is going to trigger the OnChanged handler every time a file is changed. I'm amazed that you only managed to receive hundreds of messages for a single file!

The method will never terminate cleanly, so a quick-and-dirty fix would be to move the creation of the FileSystemWatcher instance outside of the loop:
C#
public static void RunEventListenerPrgm()
{
    var m_Watcher = new System.IO.FileSystemWatcher
    {
        Filter = "*.txt",
        Path = @"C:\EventListenerFolder\",
        NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName
    };
    
    m_Watcher.Created += OnChanged;
    m_Watcher.EnableRaisingEvents = true;
    
    while (true)
    {
    }
}

However, this will probably consume 100% of one of your CPU cores all the time the program is running!

A slightly better alternative would be to use the WaitForChanged method:
C#
public static void RunEventListenerPrgm()
{
    var m_Watcher = new System.IO.FileSystemWatcher
    {
        Filter = "*.txt",
        Path = @"C:\EventListenerFolder\",
        NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName
    };
    
    while (true)
    {
        WaitForChangedResult result = m_Watcher.WaitForChanged(WatcherChangeTypes.Created | WatcherChangeTypes.Changed);
        if (!result.TimedOut)
        {
            OnChanged(result.Name);
        }
    }
}

private static void OnChanged(string file)
{
    Console.WriteLine("EventListener Match File Found. FILE NAME : {0}", file);
    
    try
    {
        string stringReceived = File.ReadAllText(file);
        SendMailFunction(stringReceived);
        File.Delete(file);
    }
    catch (IOException)
    {
    }
}

Ideally, you'd need to find some way to notify the method when your application was closing, so that it could stop the loop cleanly.

Finally, there is a known issue where the FileSystemWatcher can generate multiple events for the same change. There are numerous workarounds to be found - for example:
FileSystemWatcher Changed event is raised twice - Stack Overflow[^]
FileSystemWatcher generates duplicate events – How to workaround – BizTalk 2006 – Windows SharePoint Services adapter[^]
 
Share this answer
 
v2

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900