FileSystemWatcher stops catching events
Asked Answered
A

4

25

I am writing a c# program to let me know when a file has been added or deleted. I run it on my Windows 7 machine and watch an FTP server on our network.

It works fine but will suddenly stop catching any events. I'm guessing that it might be losing connection to the server or there is a glitch in the network.

How can I handle this situation in the code. Is there some exception I can watch for and try to restart the FileSystemWatcher object.

Any suggestions and code samples would be appreciated.

Adventurous answered 31/5, 2011 at 7:9 Comment(4)
So if 1kb of the file has been uploaded, how do you know the transmission is complete? I think you need to rethink your approach here.Wellestablished
Check out this question about exceptions when reading created files with the FileSystemWatcher #700038Eastsoutheast
It works fine to capture when files are created or deleted. I just need to know how to recover from the lost connection or network glitch. Is there any type of exception thrown on the FileSystemWatcher object?Adventurous
I think I know what I need to do now. Catch the exception that the fileSystemWatcher throws and then try to re-enable raising events on it when the server is accessible again. I don't understand where I would put the try/catch at.Adventurous
K
17

The previous answer does not fix it completely, I had to reset the watcher not just turn it on and off. I use filesystemwatcher on a window service

void NotAccessibleError(FileSystemWatcher source, ErrorEventArgs e)
{
    int iMaxAttempts = 120;
    int iTimeOut = 30000;
    int i = 0;
    while ((!Directory.Exists(source.Path) || source.EnableRaisingEvents == false) && i < iMaxAttempts)
    {
        i += 1;
        try
        {
            source.EnableRaisingEvents = false;
            if (!Directory.Exists(source.Path))
            {
                MyEventLog.WriteEntry("Directory Inaccessible " + source.Path + " at " + DateTime.Now.ToString("HH:mm:ss"));
                System.Threading.Thread.Sleep(iTimeOut);
            }
            else
            { 
                // ReInitialize the Component
                source.Dispose();
                source = null;
                source = new System.IO.FileSystemWatcher();
                ((System.ComponentModel.ISupportInitialize)(source)).BeginInit();
                source.EnableRaisingEvents = true;
                source.Filter = "*.tif";
                source.Path = @"\\server\dir";
                source.NotifyFilter = System.IO.NotifyFilters.FileName;
                source.Created += new System.IO.FileSystemEventHandler(fswCatchImages_Changed);
                source.Renamed += new System.IO.RenamedEventHandler(fswCatchImages_Renamed);
                source.Error += new ErrorEventHandler(OnError);
                ((System.ComponentModel.ISupportInitialize)(source)).EndInit();
                MyEventLog.WriteEntry("Try to Restart RaisingEvents Watcher at " + DateTime.Now.ToString("HH:mm:ss"));
            }
        }
        catch (Exception error)
        {
            MyEventLog.WriteEntry("Error trying Restart Service " + error.StackTrace + " at " + DateTime.Now.ToString("HH:mm:ss"));
            source.EnableRaisingEvents = false;
            System.Threading.Thread.Sleep(iTimeOut);
        }
    }
}
Kujawa answered 11/10, 2012 at 23:56 Comment(3)
this seems to keep looping and re-creating the filesystemwatcher even if it is successful at some point. Shouldn't there be a break in the "success" loop?Walford
@Walford It should break on 1) path exists (accessible) and b)EnableRaisingEvents == true.Grief
This assigns a new FileSystemWatcher to a local variable. The caller still has a reference to the old instance, which is now disposed.Kapp
A
24

I needed to add an error handler for the FileSystemWatcher

fileSystemWatcher.Error += new ErrorEventHandler(OnError);

And then add this code:

private void OnError(object source, ErrorEventArgs e)
{
    if (e.GetException().GetType() == typeof(InternalBufferOverflowException))
    {
        txtResults.Text += "Error: File System Watcher internal buffer overflow at " + DateTime.Now + "\r\n";
    }
    else
    {
        txtResults.Text += "Error: Watched directory not accessible at " + DateTime.Now + "\r\n";
    }
    NotAccessibleError(fileSystemWatcher ,e);
}

Here is how I reset the SystemFileWatcher object:

   static void NotAccessibleError(FileSystemWatcher source, ErrorEventArgs e)
    {
        source.EnableRaisingEvents = false;
        int iMaxAttempts = 120;
        int iTimeOut = 30000;
        int i = 0;
        while (source.EnableRaisingEvents == false && i < iMaxAttempts)
        {
            i += 1;
            try
            {
                source.EnableRaisingEvents = true;
            }
            catch
            {
                source.EnableRaisingEvents = false;
                System.Threading.Thread.Sleep(iTimeOut);
            }
        }

    }

I think this code should do what I want it to do.

Adventurous answered 31/5, 2011 at 7:9 Comment(2)
If this does indeed fix the problem you should mark it as the answer. For what it's worth, what was the exception that was being thrown?Karolinekaroly
Chris, Actually I am not concerned with what the exception is I just want to make sure the FileSystemWatcher object is restarted.Adventurous
K
17

The previous answer does not fix it completely, I had to reset the watcher not just turn it on and off. I use filesystemwatcher on a window service

void NotAccessibleError(FileSystemWatcher source, ErrorEventArgs e)
{
    int iMaxAttempts = 120;
    int iTimeOut = 30000;
    int i = 0;
    while ((!Directory.Exists(source.Path) || source.EnableRaisingEvents == false) && i < iMaxAttempts)
    {
        i += 1;
        try
        {
            source.EnableRaisingEvents = false;
            if (!Directory.Exists(source.Path))
            {
                MyEventLog.WriteEntry("Directory Inaccessible " + source.Path + " at " + DateTime.Now.ToString("HH:mm:ss"));
                System.Threading.Thread.Sleep(iTimeOut);
            }
            else
            { 
                // ReInitialize the Component
                source.Dispose();
                source = null;
                source = new System.IO.FileSystemWatcher();
                ((System.ComponentModel.ISupportInitialize)(source)).BeginInit();
                source.EnableRaisingEvents = true;
                source.Filter = "*.tif";
                source.Path = @"\\server\dir";
                source.NotifyFilter = System.IO.NotifyFilters.FileName;
                source.Created += new System.IO.FileSystemEventHandler(fswCatchImages_Changed);
                source.Renamed += new System.IO.RenamedEventHandler(fswCatchImages_Renamed);
                source.Error += new ErrorEventHandler(OnError);
                ((System.ComponentModel.ISupportInitialize)(source)).EndInit();
                MyEventLog.WriteEntry("Try to Restart RaisingEvents Watcher at " + DateTime.Now.ToString("HH:mm:ss"));
            }
        }
        catch (Exception error)
        {
            MyEventLog.WriteEntry("Error trying Restart Service " + error.StackTrace + " at " + DateTime.Now.ToString("HH:mm:ss"));
            source.EnableRaisingEvents = false;
            System.Threading.Thread.Sleep(iTimeOut);
        }
    }
}
Kujawa answered 11/10, 2012 at 23:56 Comment(3)
this seems to keep looping and re-creating the filesystemwatcher even if it is successful at some point. Shouldn't there be a break in the "success" loop?Walford
@Walford It should break on 1) path exists (accessible) and b)EnableRaisingEvents == true.Grief
This assigns a new FileSystemWatcher to a local variable. The caller still has a reference to the old instance, which is now disposed.Kapp
C
0

You can create a method that initiates the FileSystemWatcher, and in case of an error, just restart it.

    private void WatchFile()
    {
        try
        {
            fsw = new FileSystemWatcher(path, filter)
            {
                EnableRaisingEvents = true
            };                
            fsw.Changed += Fsw_Changed;                
            fsw.Error += Fsw_Error;
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
    }

    private void Fsw_Error(object sender, ErrorEventArgs e)
    {
        Thread.Sleep(1000);
        fsw.Changed -= Fsw_Changed;
        fsw.Error -= Fsw_Error;
        WatchFile();
    }
Cayman answered 5/12, 2019 at 15:58 Comment(2)
Each time the system raise an error you create a new FileSystemWatcher. I think you are going to a stack overflow exception.Yeisk
WHat if a file is created while the events are detached, you will miss the file right?Organza
B
-1

I solved this problem by raising the:

(name of FileSystemWatcher).InternalBufferSize = MyInternalBufferSize
Read(FileSystemWatcher.InternalBufferSize Property)

(Documentation)

I tested it with an InternalBufferSize at max 64 KB and placed 320 dummy files in the FileSystemWatcher path and it ran like Speedy Gonzales.

Bernetta answered 12/10, 2023 at 11:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.