The FileSystemWatcher control allows you to easily monitor a directory or set of directories. It raises events when files are added, deleted and updated and lets you perform actions cooresponding to those events.
At work, I have an application that allows users to upload image files to one of our web servers to be used on our web site. For the longest time now, someone has been manually copying those images to the rest of the servers on our web farm.
The first thing I know you are going to say is, "Do you know they have something called files replication?"
Let me just say...
1) I do know what file replication is.
2) It would have been a lot easier to use file replication to accomplish this.
However, I don't want to waste your time as to why the operations guys at my company wont use file replication. Hint...they deleted all the files off one of our servers once, and now they are scared of it. Oops, was that my outloud voice? :-o
I decided to create a service that would constantly monitor the one server and copy the new and updated files to the other servers. Honestly, the service only took me about 30 minutes to write, and that was with taking time to to figure out how to use the FileSystemWatcher control and remembering how to install and debug a service.
First I created a new C# Windows Service.
Next I created a configuration file for the service that had a setting for the source server and the targetservers. The contents of the file looked like:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<sourceserver name="name of server to copy from" path="path on the server to monitor"/>
<targetserver name="name of server to copy files to" path="path on server to copy to"/>
</configuration>
You can set as many targetservers as you like.
After Visual Studio created the files for the project I only had to make a few edits to the code. First I had to add two private variables to the FileWatcher class:
private XmlDocument Config;Next I added this code when the service starts:
private System.Collections.Hashtable TargetServers;
private FileSystemWatcher FileWatcher;
this.FileWatcher.EnableRaisingEvents = true;Since I want to perform the same action when a file is changed or updated, I set the event handlers of both events to call the same function.
this.FileWatcher.Changed += new System.IO.FileSystemEventHandler(this.FileWatcher_Changed);
this.FileWatcher.Created += new System.IO.FileSystemEventHandler(this.FileWatcher_Changed);
After that, I updates the OnStart function to look like this:
protected override void OnStart(string[] args)Finally, I added the function to execute for the FileWatcher_Changed event:
{
Config = new XmlDocument();
TargetServers = new Hashtable();
string localpath = System.IO.Path.GetDirectoryName(
System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase );
//load the config file
try
{
Config.Load(localpath+"\\config.xml");
}
catch (System.Xml.XmlException xex)
{
this.EventLog.WriteEntry("Could not open config file. Error was:\n"+xex.Message,System.Diagnostics.EventLogEntryType.Error,1,1);
}
//set the path that the filesystemwatcher will watch
FileWatcher.Path = Config.SelectSingleNode("configuration/sourceserver/@path").Value;
//fill the TargetServers Hashtable with all the target servers that we will copy the files to.
foreach (XmlNode node in Config.SelectNodes("configuration/targetserver"))
{
TargetServers.Add(node.SelectSingleNode("@name").Value,node.SelectSingleNode("@path").Value);
}
//set the file properties filesytemwatcher uses to detect changes to files
FileWatcher.NotifyFilter=NotifyFilters.FileName | NotifyFilters.LastWrite | NotifyFilters.Size;
FileWatcher.IncludeSubdirectories=false;
}
private void FileWatcher_Changed(object sender, System.IO.FileSystemEventArgs e)The one last thing I needed to do was add the installer. Just right click on the designer for the services class files and select Create Installer. Save and build the Solution.
{
IDictionaryEnumerator ListEnumerator = TargetServers.GetEnumerator();
try
{
switch (e.ChangeType)
{
case WatcherChangeTypes.Created:
while (ListEnumerator.MoveNext())
{
File.Copy(e.FullPath, ListEnumerator.Value.ToString()+"\\"+e.Name, true);
}
break;
case WatcherChangeTypes.Changed:
while (ListEnumerator.MoveNext())
{
File.Copy(e.FullPath, ListEnumerator.Value.ToString()+"\\"+e.Name, true);
}
break;
}
}
catch (IOException ix)
{
this.EventLog.WriteEntry("IOException while copying files. Error was:\n"+ix.Message,System.Diagnostics.EventLogEntryType.Error,1,1);
}
catch (Exception x)
{
this.EventLog.WriteEntry("Unknown Exception while copying files. Error was:\n"+x.Message,System.Diagnostics.EventLogEntryType.Error,1,1);
}
}
To install the service, run the following in the directory where the exe for the service was created:
installutil filewatcher.exeYou can then start the service either in the Services Control Panel.
If you need to debug the service, you can attach to the process and then set breakpoints as long as you have created a debug build.
References I used while writing my code:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbcon/html/vborireactingtofilesystemevents.asp
Hi Jason!
I like your FileSystemWatcher code. We run a similar situation here (three satellite web servers and one big primary one). In looking at your code, however, I don't see the Deleted event being handled. How do you handle when a file should be removed from the servers?
Thanks in advance!
Posted by: Jody Farr | Monday, January 19, 2004 at 10:51 AM
Jody,
In my situation, I never need to delete the files because we keep them around for historical purposes.
If you want to delete files, it is pretty simple. Just update the FileWatcher_Changed function to respond to delete events. Add another Case to the Switch for WatcherChangeTypes.Deleted. In that Case, change the File.Copy method call to File.Delete(ListEnumerator.Value.ToString()+"\\"+e.Name). As long as the user the service is running under has the proper permission to delete files from the directories on all three servers, it should work.
Posted by: Jason | Monday, January 19, 2004 at 10:26 PM
Jason,
Great article - I wish I had read it before MS's. I have a service that does a very similar thing, only it worked immediately and then when subsequent files are placed in the directory - it doesn't seem to fire. Does it have to be reset? And if so, how?
Thanks!
Posted by: Adam | Friday, January 23, 2004 at 05:30 PM
Not, it does not need to be reset. I had a similiar problem when I first started running the service. I found that the file.copy method ca't overwrite files that are set to read-only. So make sure that all the files in the directories you are copying files to as not set to read-only.
Posted by: Jason | Sunday, January 25, 2004 at 06:17 PM
Can someone help me with the following problem:
I have created a FileSystemWatcher (fsw) to monitor creation of *.txt file on a mapped directory (the directory is on a Win98 system) the application works fine (events are triggering) when it is running on an XP system, but the same application did not get any event trigger when it is running on a Win2K system. Any idea?
Posted by: sweet | Monday, January 26, 2004 at 11:14 PM
There are a number of things that could be wrong. Create some event log entries during the different service events to verify that the service is starting and running correctly. Have you tried debugging the service? Maybe you can step through the code as it is running. The first thing I would check is that the user you are running the service under has the necessary permissions on the 2K machine. Good Luck.
Posted by: Jason | Tuesday, January 27, 2004 at 09:40 PM
Jason,
I've written a similar service, but I need to go one step further and indentify the user who created the file - I haven't found a way of doing this yet, would you have any ideas?
Thanks.
Posted by: Steve | Wednesday, January 28, 2004 at 11:54 AM
What do you do if the file takes a while to write...like downloading.
Posted by: Gordon | Monday, February 02, 2004 at 09:14 PM
i have the same question as Gordon: what if the file is huge in size and takes a long time to write on the disk? is there an implementation of "WriteComplete" event for a file? normally you don't want to touch the file until it is completely on the file system
Posted by: Tau | Friday, February 13, 2004 at 02:54 PM
Hello! I have one question: when I handle Deleted event the parameter supplied is FileSystemEventArgs.FullPath (i.e. path to the deleted file or directory). In my application I provide specific logic for files and directories. How I can determine that the deleted is file/directory?? The file system object already doesn't exists, so I can't use File.Exists() or Directory.Exists()???
Posted by: Nikolai | Wednesday, March 10, 2004 at 06:27 AM
There seems to be huge inconsistency when I run a FSW on Windows 2003 Server box, as opposed to a Windows XP box, both of which are monitoring a network share directory. Windows XP box seems to pick up 1000 file change events, whereas, Windows 2003 box seems to pick up only 250 events.
Does anybody know of any network file event conditions on Windows 2003, that could be causing this?
Is it generally a bad idea to watch for file change events over the network?
Any ideas or suggestions will help.
Posted by: Burde Praje | Friday, June 04, 2004 at 08:23 AM
Hi,
Liked your article.. in my case files are being copied to source directory (its on network).. and then moved to target directory automatically using FSW.. If the files being copied to source directory are big then, event is being fired but since whole file is not yet copied to source, it result into an error while moving to target.. any idea how to solve this error.
regards,
Nilay
Posted by: Nilay Shah | Saturday, June 12, 2004 at 02:46 AM
Hey Jason,
can you please upload your FileSystemWatcher source code?
Thanks,
Stephen
Posted by: Stephen | Tuesday, January 24, 2006 at 01:38 PM
Hi:
I created an application which is supposed to move files from one directory to another. The first folder recieves files from FTP. I have scheduled the application, using windows scheduler, to be run daily. I am using the FileSystemWatcher and its events. Here is my code:
class MainClass
{
///
/// The main entry point for the application.
///
//static bool boolcreated = true;
[STAThread]
static void Main(string[] args)
{
FileSystemWatcher fsw = new FileSystemWatcher();
((System.ComponentModel.ISupportInitialize)(fsw)).BeginInit();
fsw.Path = @"C:\MonitorFolderWindowService";
fsw.IncludeSubdirectories = false;
//fsw.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite |
// NotifyFilters.FileName | NotifyFilters.DirectoryName;
//fsw.NotifyFilter=NotifyFilters.Size;
//fsw.Changed += new FileSystemEventHandler(OnChanged);
fsw.Created += new FileSystemEventHandler(OnChanged);
//fsw.Deleted += new FileSystemEventHandler(OnChanged);
//fsw.Renamed += new RenamedEventHandler(OnRenamed);
// Begin watching.
fsw.EnableRaisingEvents = true;
((System.ComponentModel.ISupportInitialize)(fsw)).EndInit();
Console.ReadLine();
}
//define event handlers
private static void OnChanged(Object Sender, FileSystemEventArgs e)
{
string ChangeType = e.ChangeType.ToString();
if (ChangeType=="Created")
{
try
{
FileInfo fi = new FileInfo(e.FullPath);
if(fi.LastWriteTime >= DateTime.Now)
{
Console.WriteLine("still writing");
}
else
{
Console.WriteLine("done writing");
// MOVE THE FILE
// ** Check first whether the file still exists
// ** if exists, move the file
// ** else ignore the operation
if(File.Exists(fi.FullName))
{
fi.MoveTo( @"C:\MonitorFolderWindowService2\"+e.Name);
return;
}
}
}
catch(IOException ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
}
}//class
When a file is copied to the first folder, the FileSystemWatcher created event is fired twice. I added the code to check for the file and it is not throwing exception now.
THe problem i am facing is when a number of files are copied to the first folder at a time, only the first file gats moved to the second folder.
Any help will be appreciated
Posted by: Shazia | Friday, April 21, 2006 at 04:00 PM
I had a console application that monitors and xml file for changed and loads new information into it. By i seems to have encountered a weird problem in where the onchange event doesn not trigger when edited and modified using visual studio. Does anyone know why ?
Posted by: renold | Friday, March 09, 2007 at 05:55 AM
can i use FileSystemWatcher to monitor when a file is drop or open in ftp folder(ftp server)
Posted by: henry | Friday, July 04, 2008 at 04:32 PM
No You can't use FileSystemWatcher for ftp path
Posted by: Venkat | Friday, August 01, 2008 at 07:26 AM
Writing an exact man,i admire you.
Posted by: air jordans | Thursday, November 11, 2010 at 02:14 AM
I want to bring out the secrets of nature and apply them for the happiness of man . I don't know of any better service to offer for the short time we are in the world .(Thomas Edison , American inventor)
Posted by: outlet moncler | Tuesday, December 13, 2011 at 02:36 AM
Every man is his own worst enemy
Posted by: woolrich outlet | Saturday, December 17, 2011 at 09:21 PM
Hi Newbie, and you are not wrong, valid request, proepr location (Mutual Aid)& valid link. Unfortunately this is a relatively new file and I have not seen it yet. (I'd also like to have it as the Nursoda characters are among my favorites ) If I do, I'll make it available. 0Was this answer helpful?
Posted by: Malik | Friday, April 27, 2012 at 08:57 PM