views:

1954

answers:

5

I need to have a FileSystemWatcher run in an infinite loop to monitor a file for changes, but this file will only change every few days, and maybe only once a week. In the MSDN sample of a FileSystemWatcher, there is a loop while the user doesn't enter q at the console:

while(Console.Read()!='q');

I don't want this to be constantly available so it isn't accidentally killed - it has to run with no user intervention in an infinite loop. Do I have to change the loop to

while (true);

so the thread doesn't exit? This alone isn't ideal as it will peg the CPU - adding a Thread.Sleep call would eliminate the CPU load, and in this case, could be a long sleep as the file very rarely changes. Is this the best way to go? How should I make sure this thread remains alive so the FileSystemWatcher can act when a file changes? This is running on a Windows server(with .NET framework version 2.0), so making it a Windows service would be possible if necessary.

A: 

You could use Thread.Sleep to avoid the empty loop. However, in the event of e.g. a system reboot the Windows Service will be restarted automatically. Another approach, depending on how the rest of the program/system is architected is to use the Windows Scheduler to run the polling logic in a separate .exe file.

If you are looking for a robust/resilient solution, either the Windows service or the Windows Scheduler-based approach seem preferable.

Jason Weber
A: 

Sysinternals (now owned by Microsoft) has FileMon which will give you what you need, with source.

Quoting from the site

the heart of FileMon is in the virtual device driver, Filevxd.vxd. It is dynamically loaded, and in its initialization it installs a file system filter via the VxD service, IFSMGR_InstallFileSystemApiHook, to insert itself onto the call chain of all file system requests.

Binaries and sources can be found here: http://technet.microsoft.com/en-us/sysinternals/bb896642.aspx

Michael McCarty
The source code is actually for a quite old version. The IFS Kit at http://www.microsoft.com/whdc/devtools/ifskit/default.mspx provides updated source code (one of the examples it provides is the same as used by FileMon and the underlying ReadDirectoryChanges Win32 call).
Not Sure
+3  A: 

If this is running on a server, a service seems like a good bet.

If you want something a little more interactive, I have a small application that lives in my system tray to show me when something happens in our Issues folder. It uses the Application.Run() method to keep itself going without the need for a loop, i.e.

class MainEntryClass
{
    static void Main(string[] args)
    {
        FolderAlerter fa = new FolderAlerter(); 
        Application.Run();
    }
}

Then I set up my FileSystemWatcher in FolderAlerter.

aehiilrs
A: 

Basically, FileSystemWatcher is using some of the built-in hooks to subscribe to changes and just gets the OS to call your delegates when a change occurs. So all you have to do is stop your main thread from exiting, it doesn't have to actually do anything; By the time you get to that line, the main part of your program is over, it has done what it needed to do.

A simple way of doing what you want is to make this change to the sample from MSDN;

//while (Console.Read() != 'q') ;
System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);

This will put your main thread to sleep forever, but will still allow the delegates to fire and respond to changes in the directory. Note that it will keep running through multiple changes (just like the MSDN sample).

Note that the "while" in the MSDN sample doesn't really do much; You could replace that line with just "Console.Read()", which would then make any key quit the application. It's just a line to stop the main thread from exiting so that it is still around when the event notifications come in.

However, using the Sleep(Timeout.Infinite) leaves your app in a state where it cannot be easily stopped by a user, other than by killing the app. If you are writing this as a console app, why not stick with the "press Q to quit"? If you decide to write it as a service instead it will probably be OK, as long as you handle the shutdown/restart events etc.

Frans
Application.Run() is a better method because it sets up the required message processing loop. I'm not sure, but I think this method will trigger the "application not responding" message when the users tries to shut down Windows.
Jesse Weigert
It didn't in my test - but I agree, it's not a good way to do it, hence my "However..." :)
Frans
A: 

To do this, you probably want to create a ManualResetEvent in a reset state and have your main thread WaitOne() on it. To terminate, some other callback can simply Set() the event which will cause WaitOne() to return.

Jeffrey Hantin