jakey  
 

一.前言

我们知道FileSystemWatcher 类用来侦听文件系统更改通知,并在目录或目录中的文件发生更改时引发事件。 在我们刚刚结束的项目当中也用到.NET的这个类。关于这个类的使用诸多帮助文档和搏友们都有过精彩的描述。

我们现在大概回顾一下这个类的基本特性:使用 FileSystemWatcher 监视指定目录中文件的创建,更改,删除,也可监视指定目录中的文件或子目录的创建,更改,删除等事件。可以创建一个组件来监视本地计算机、网络驱动器或远程计算机上的文件。可监视目录或文件中的若干种更改。例如,可监视文件或目录的 AttributesLastWrite 日期和时间或 Size 方面的更改。通过将 NotifyFilter 属性设置为 NotifyFilters 值之一来达到此目的。有关可监视的更改类型的更多信息。

不过关于FileSystemWatcher类的错误处理部分,资料却显得相对少很多,MSDN上也几乎没有给出相关的介绍和例子。比如我们用FileSystemWatcher类来监控一个局域网或者远程机器的一个目录,在软件运行的情况下,网络突然出现问题,抑或,远程监控的目录被删除的情况下,即便此时网络恢复,或远程目录重建,FileSystemWatcher 也无法恢复正常工作状态。所以FileSystemWatcher类就应该有相应的处理,使得FileSystemWatcher对象从错误中恢复,对接下来发生的创建,更改,删除 等事件做出响应

二.正文

下面我们来看一下几段程序,在接下来的描述中来体会FileSystemWatcher错误处理的一个简单实例。希望能有用处。

在一般性的项目中,对于出现网络不通等错误时,需要进行重试,以便通过重试将系统从错误当中恢复。那么我们先来介绍一个用C#写的来进行局域网中的重试方法,这个方法将会在后面的方法中用到。


 1/// <summary>
 2        /// Checks the Temporary folder connection when application start. If can't connect,
 3        /// this method will retry to connect, using the specified retry number and
 4        /// retry interval time in configuration file.
 5        /// </summary>
 6        /// <returns>Returns true if successfully connect to folder.
 7        /// Returns false if can't connect to folder after retrying.</returns>

 8        public bool CheckMonitorPath(string strMonitorPath, int nRetryInterval, int nMaxRetryCount)
 9        {
10            // The temporary folder path existence flag
11            bool bTemporaryPathExist = false;
12
13            if (!Directory.Exists(strMonitorPath))
14            {
15                if (nMaxRetryCount < 0)
16                {
17                    // Retry to connect the Temporary folder
18                    CLogger.log.Info("MSG_INFO_STARTUP_CONNECT", strMonitorPath);
19                    int i = 0;
20                    for (; ; i++)
21                    {                        
22                        if (RetryConnectFolder(i, nRetryInterval, strMonitorPath))
23                        {
24                            bTemporaryPathExist = true;
25                            break;
26                        }

27                    }

28                }

29                else
30                {
31                    // Retry to connect the Temporary folder
32                    CLogger.log.Info("MSG_INFO_STARTUP_CONNECT", strMonitorPath);
33                    int i = 0;
34                    for (; i < nMaxRetryCount; i++)
35                    {
36                        if (RetryConnectFolder(i, nRetryInterval, strMonitorPath))
37                        {
38                            bTemporaryPathExist = true;
39                            break;
40                        }

41                    }

42                    if (nMaxRetryCount == i)
43                    {
44                        CLogger.log.Error("MSG_ERROR_RETRYCONNECTFAILED", strMonitorPath, i.ToString());
45                        bTemporaryPathExist = false;
46                    }

47                }

48            }

49            else
50            {
51                bTemporaryPathExist = true;
52            }

53            return bTemporaryPathExist;
54        }

55
56         /// <summary>
57         /// Retry to connect the monitoring folder
58         /// </summary>
59         /// <param name="nCounter">The retry time</param>
60         /// <param name="nRetryInterval">The retry interval time</param>
61         /// <param name="strMonitorPath">The monitored path retry to connect</param>
62         /// <returns>true: retry connect success, false: retry connect failed</returns>         

63         private bool RetryConnectFolder(int nCounter, int nRetryInterval, string strMonitorPath)
64         {
65             if (0 != nCounter)
66             {
67                 CLogger.log.Debug("MSG_DEBUG_STARTUP_CONNECT_RETRY", nCounter.ToString());
68             }

69             else
70             {
71                 CLogger.log.Debug("MSG_DEBUG_STARTUP_CONNECT_RETRY", strMonitorPath);
72             }

73             try
74             {
75                 if (Directory.Exists(strMonitorPath))
76                 {
77                     // If the Temporary folder connect successfully
78                     CLogger.log.Info("MSG_INFO_STARTUP_CONNECT_RETRYSUCCESS", strMonitorPath, nCounter.ToString());
79                     return true;
80                 }

81             }

82             catch (Exception ex)
83             {
84                 CLogger.log.Error("MSG_ERROR_RETRYCONNECT_EXCEPTION", ex);
85                 return false;
86             }

87             //  Retry to connect the temporary folder with certain interval time
88             Thread.Sleep(nRetryInterval * 1000);
89             return false;
90}

91


接下来的这个方法是对FileSystemWatcher类的使用,其中包括将要监控的文件夹路径,可监视文件或目录的 AttributesLastWrite 日期和时间或 Size 方面的更改。通过将 FileSystemWatcher.NotifyFilter 属性设置为 NotifyFilters 值之一来达到此目的。有关可监视的更改类型的更多信息。

在这个函数中,我们重点介绍FileSystemWatcher类的Error事件,通过此事件的捕捉,从而作相应的错误处理。
 1/// <summary>
 2        /// The watcher method, to sense whether there is new file 
 3        /// is created in the network/local folder
 4        /// </summary>

 5        public void SystemWatch()
 6        {
 7            try
 8            {
 9                watcher.Path = RemoteMonitorPath;
10                watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName;
11                // Sub-folder of the root can be monitored
12                watcher.IncludeSubdirectories = true;
13                watcher.Filter = "*.*";
14                watcher.Created += new FileSystemEventHandler(OnChanged);
15                // Add the event handlers: this event raised when it detects an error
16                watcher.Error += new ErrorEventHandler(WatcherError);
17                watcher.EnableRaisingEvents = true;
18
19                CLogger.log.Info("MSG_INFO_WATCHER_START");
20                while (!bStop)
21                {
22                    oEvent.WaitOne();
23                }

24                CLogger.log.Info("MSG_INFO_WATCHER_STOP");
25            }

26            catch (ArgumentException ex)
27            {
28                CLogger.log.Error("MSG_ERROR_WATCHER_RUNTIMEEXCEPTION", ex);
29            }

30            catch (FileNotFoundException ex)
31            {
32                CLogger.log.Error("MSG_ERROR_WATCHER_RUNTIMEEXCEPTION", ex);
33            }

34            catch (DirectoryNotFoundException ex)
35            {
36                CLogger.log.Error("MSG_ERROR_WATCHER_RUNTIMEEXCEPTION", ex);
37            }
            
38            catch (Exception ex)
39            {
40                CLogger.log.Error("MSG_ERROR_WATCHER_RUNTIMEEXCEPTION", ex);
41            }

42        }

43
   

下面这个函数就是本文的重点,是FileSystemWatcher类的错误处理的函数,当发生监控路径错误时(网络问题,或者所监控文件夹被删除等),FileSystemWatcher类会自动捕捉错误,然后这个函数被调用,将FileSystemWatcher类从死亡中拯救出来。

 1/// <summary>
 2        /// The error event handler
 3        /// </summary>
 4        /// <param name="source">The object instance</param>
 5        /// <param name="e">The ErrorEventArgs instance</param>

 6        private void WatcherError(object source, ErrorEventArgs e)
 7        {
 8// Retry interval and max retry time (times)
 9            nRetryInterval = alertConfigValues.TempConnectInterval;
10            nMaxRetryCount = alertConfigValues.TempMaxRetryCount;
11            try
12            {
13                Exception watchException = e.GetException();
14                CLogger.Log.Error("MSG_ERROR_FILESYSTEMWATCHER_ERROROCCURS", watchException.Message);
15
16                if (netSniffer.CheckMonitorPath(RemoteMonitorPath, nRetryInterval, nMaxRetryCount))
17                {
18                    int nRetryCounter = 0;                    
19                    // We need to create new version of the object because the
20                    // old one is now corrupted
21                    watcher = new FileSystemWatcher();
22                    while (!watcher.EnableRaisingEvents)
23                    {
24                        try
25                        {
26                            // This will throw an error at the
27                            // watcher.NotifyFilter line if it can't get the path.
28                            SystemWatch();
29                            Thread.Sleep(nRetryInterval * 1000);
30                            nRetryCounter++;
31
32                            if (nMaxRetryCount == nRetryCounter)
33                            {
34                                break;
35                            }

36                        }

37                        catch
38                        {
39                            // Sleep for a while; otherwise, it takes a bit of
40                            // processor time
41                            Thread.Sleep(nRetryInterval * 1000);
42                        }

43                    }
                    
44                    // Stop the watcher
45                    CLogger.Log.Error("MSG_ERROR_FILESYSTEMWATCHER_RETRYFAILED ");
46                }

47                else
48                {              
49                    // Stop the watcher
50                    CLogger.Log.Error("MSG_ERROR_FILESYSTEMWATCHER_RETRYFAILED ");
51                }

52            }

53            catch (Exception ex)
54            {
55                CLogger.Log.Error("MSG_ERROR_FILESYSTEMWATCHER_ERROROCCURS", ex);
56            }

57 }

58


通过对于错误的处理FileSystemWatcher又活过来了,这下它又可以正常工作了。我们可以直观地看一个截图。

 

三.后记

当初也是因为在做项目的时候遇到这个问题,即便恢复网络连接/重建文件夹FileSystemWatcher却无法再工作了,在百般苦恼与挣扎中才找到解决的办法,其实微软本来就提供的关于Error事件处理的使用办法,只不过没有明确讲明白其用法而已。

我写这篇短短小文的初衷,也仅仅是为了记录一下所谓心路历程,在工作的过程中,这个问题给我留下了很深的映像,同时也希望博友们如果遇到相似问题,这篇小文也许会有一些用处。


posted on 2006-08-04 18:54  jakey  阅读(1846)  评论(3编辑  收藏  举报