I have made a tiny application that responds to changes to files in a folder. But when I edit the file in Visual Studio 2008, it never detects anything. If I edit the file in Notepad instead, everything works as expected.
Surely Visual Studio saves the file at some point, but the watcher does not even trigger when I close the studio. Do you have any idea what I'm missing here?
This sample code (C#) should illustrate the problem:
FileSystemWatcher fileSystemWatcher = new FileSystemWatcher("C:\Test", "*.cs");
WaitForChangedResult changed = fileSystemWatcher.WaitForChanged(WatcherChangeTypes.All);
Console.Out.WriteLine(changed.Name);
I found a blog post by Ayende that describes the same problem, but unfortunately no solution.
This was really mind boggling... when you try my example program below and change the file in VS, you will notice two lines in your output window:
Deleted
Renamed
So Visual Studio does never change an existing file, it saves the constents to a new file with a temporary name, then deletes the original file and renames the new file to the old name.
Actually, this is a good practice, because if you do it the usual way (just writing the changed file, which would cause the Changed
event to be fired), the event handler may be called before the writing process is complete. If the event handler processes the file contents, this may cause problems because it would process an incomplete file.
In other words: It's not a bug, it's a feature ;-)
static class Program
{
[STAThread]
static void Main()
{
FileSystemWatcher FSW = new FileSystemWatcher("c:\\", "*.cs");
FswHandler Handler = new FswHandler();
FSW.Changed += Handler.OnEvent;
FSW.Created += Handler.OnEvent;
FSW.Deleted += Handler.OnEvent;
FSW.Renamed += Handler.OnEvent;
FSW.EnableRaisingEvents = true;
System.Threading.Thread.Sleep(555000);
// change the file manually to see which events are fired
FSW.EnableRaisingEvents = false;
}
}
public class FswHandler
{
public void OnEvent(Object source, FileSystemEventArgs Args)
{
Console.Out.WriteLine(Args.ChangeType.ToString());
}
}
}