1, problem description
The program needs to monitor file changes in a directory: Once a new file appears in the directory or the old file is overwritten, the program needs to read the file contents and process it. The following code is used:
Public voidInitial () {System.IO.FileSystemWatcher FSW=NewSystem.IO.FileSystemWatcher (); Fsw. Filter="*.*"; Fsw. NotifyFilter= Notifyfilters.filename |Notifyfilters.lastwrite|Notifyfilters.creationtime; //ADD event handlers.Fsw. Created + =NewFileSystemEventHandler (fsw_changed); Fsw. Changed+=NewFileSystemEventHandler (fsw_changed); //Begin watching.Fsw. EnableRaisingEvents =true; } voidFsw_changed (Objectsender, FileSystemEventArgs e) {MessageBox.Show ("Changed", e.name); }
If a file changes, the change event is repeatedly triggered several times. This may result in duplicate processing of the same file.
2. Solution:
After a timer is passed in the file event processing, the timer is delayed for a period of time before the load of the new profile operation is performed. This avoids having to do a single operation on the file, triggering multiple change events, and loading the configuration file multiple times.
The Log4net code-XmlConfigurator.cs is studied, and the following changes are made to the code by reference to Log4net:
The basic idea is to use a timer, start the timer when the event is triggered, and write down the file name. When the timer comes, the file is actually processed.
(1), defining variables
Private int - // Timer trigger Interval New null; ListNew list<string// queue to record pending files
(2), Initialize FileSystemWatcher and timers
Fsw. Filter ="*.*"; Fsw. NotifyFilter= Notifyfilters.filename |Notifyfilters.lastwrite|Notifyfilters.creationtime; //ADD event handlers.Fsw. Created + =NewFileSystemEventHandler (fsw_changed); Fsw. Changed+=NewFileSystemEventHandler (fsw_changed); //Begin watching.Fsw. EnableRaisingEvents =true; //Create the timer that'll be used to deliver events. Set as Disabled if(M_timer = =NULL) { //sets the callback function for the timer. The timer does not start at this timeM_timer =NewSystem.Threading.Timer (NewTimerCallback (onwatchedfilechange),NULL, Timeout.infinite, timeout.infinite); }
(3), file monitoring Event trigger code: Modify the timer, record the file name to be processed later
void fsw_changed (object sender, FileSystemEventArgs e) { new Mutex ( False"FSW"); Mutex. WaitOne (); if (! files. Contains (e.name)) { files. ADD (e.name); } Mutex. ReleaseMutex (); // Reset the timer's trigger interval and only trigger once M_timer. Change (Timeoutmillis, timeout.infinite); }
(4), Timer Event trigger code: The actual processing of the file
Private voidOnwatchedfilechange (ObjectState ) {List<String> backup =Newlist<string>(); Mutex Mutex=NewMutex (false,"FSW"); Mutex. WaitOne (); Backup. AddRange (files); Files. Clear (); Mutex. ReleaseMutex (); foreach(stringFileinchbackup) {MessageBox.Show ("File Change", File +"changed"); } }
Tidy up the above code and encapsulate it into a class that is more convenient to use:
Public classWatchertimer {Private intTimeoutmillis = -; System.IO.FileSystemWatcher FSW=NewSystem.IO.FileSystemWatcher (); System.Threading.Timer M_timer=NULL; List<String> files =Newlist<string>(); FileSystemEventHandler Fswhandler=NULL; PublicWatchertimer (FileSystemEventHandler watchhandler) {M_timer=NewSystem.Threading.Timer (NewTimerCallback (OnTimer),NULL, Timeout.infinite, timeout.infinite); Fswhandler=Watchhandler; } PublicWatchertimer (FileSystemEventHandler Watchhandler,intTimerInterval) {M_timer=NewSystem.Threading.Timer (NewTimerCallback (OnTimer),NULL, Timeout.infinite, timeout.infinite); Timeoutmillis=TimerInterval; Fswhandler=Watchhandler; } Public voidOnfilechanged (Objectsender, FileSystemEventArgs e) {Mutex Mutex=NewMutex (false,"FSW"); Mutex. WaitOne (); if(!files. Contains (e.name)) {files. ADD (e.name); } mutex. ReleaseMutex (); M_timer. Change (Timeoutmillis, timeout.infinite); } Private voidOnTimer (ObjectState ) {List<String> backup =Newlist<string>(); Mutex Mutex=NewMutex (false,"FSW"); Mutex. WaitOne (); Backup. AddRange (files); Files. Clear (); Mutex. ReleaseMutex (); foreach(stringFileinchbackup) {Fswhandler ( This,NewFileSystemEventArgs (watcherchangetypes.changed,string. Empty, file)); } }}
The use of the keynote program is very simple and requires only the following 2 steps:
1. Generate timer object for file monitoring
New Watchertimer (fsw_changed, Timeoutmillis);
Where fsw_changed is your own file monitoring event code, passing it to the timer object is intended to be timed to the time when the timer object can invoke your own code that is actually used to process the file. For example:
void fsw_changed (object sender, FileSystemEventArgs e) { //Read file. //Remove file from folder after reading }
2. Correlate event handlers such as FileSystemWatcher Create/change/rename/delete to timer events
New NEW Newnew FileSystemEventHandler (watcher. onfilechanged);
The purpose of this step is to notify the timer when any file monitoring event occurs, and the timer can be timed from the last occurrence of the event, and any event that precedes that time will only re-timer the timer without really triggering the file monitoring event.
Note that when you use the above code, the code that you really use to handle file-monitoring events is called with only E. The name is a value. Consider that the directory of files being monitored should already be known, so e. It is not unacceptable that FullPath be assigned a value of String.Empty.
Resolution of multiple triggering of FileSystemWatcher events in C #