FileSystemWatcher in C#

In this article, learn how to use the C# FileSystemWatcher class to watch a directory and file changes in the directory using C#.

C# FileSystemWatcher listens to the file system and places a watch on a directory, its subdirecttories, and files and notifies if any changes are made to the directory. This class is useful when you need to auto update the updates in a directory. For example, if you want to create an auto backup of a folder, you can implement a File system watcher service that watches a directory or entire machine and find when and what changes are made and copy the changes to the backup device.
C# FileSystemWatcher acts as a watchdog for file system changes and raises an event when a change occurs. You must specify a directory to be monitored. The class can monitor changes to subdirectories and files within the specified directory. If you have Windows 2000 or later OS, you can even monitor a remote system for changes. The option to monitor files with specific extensions can be set using the Filter property of the FileSystemWatcher class. You can also fine-tune FileSystemWatcher to monitor any change in file Attributes, LastAccess, LastWrite, Security, and Size data.
The FileSystemWatcher class raises the events described in Table 1.


Table 1. FileSystemaWatcher class events
Here is a complete console application that shows how to use the FileSystemWatcher in C#. The code also implements its events. You can use the same code in a Windows Service to schedule it automatically to watch a directory. The FileSystemWatcher is defined in the System.IO namespace. Make sure to import this namespace before you use the class.
Listing 1. Using the FileSystemWatcher Class using C#
  1. using System;  
  2. using System.IO;  
  3. public class FileWatcher  
  4. {  
  5. public static void Main(string[] args)  
  6. {  
  7. // If a directory is not specified, exit program.  
  8. if (args.Length != 1)  
  9. {  
  10. // Display the proper way to call the program.  
  11. Console.WriteLine("Usage: FileWatcher.exe <directory>");  
  12. return;  
  13. }  
  14. try  
  15. {  
  16. // Create a new FileSystemWatcher and set its properties.  
  17. FileSystemWatcher watcher = new FileSystemWatcher();  
  18. watcher.Path = args[0];  
  19. // Watch both files and subdirectories.  
  20. watcher.IncludeSubdirectories = true;  
  21. // Watch for all changes specified in the NotifyFilters  
  22. //enumeration.  
  23. watcher.NotifyFilter = NotifyFilters.Attributes |  
  24. NotifyFilters.CreationTime |  
  25. NotifyFilters.DirectoryName |  
  26. NotifyFilters.FileName |  
  27. NotifyFilters.LastAccess |  
  28. NotifyFilters.LastWrite |  
  29. NotifyFilters.Security |  
  30. NotifyFilters.Size;  
  31. // Watch all files.  
  32. watcher.Filter = "*.*";  
  33. // Add event handlers.  
  34. watcher.Changed += new FileSystemEventHandler(OnChanged);  
  35. watcher.Created += new FileSystemEventHandler(OnChanged);  
  36. watcher.Deleted += new FileSystemEventHandler(OnChanged);  
  37. watcher.Renamed += new RenamedEventHandler(OnRenamed);  
  38. //Start monitoring.  
  39. watcher.EnableRaisingEvents = true;  
  40. //Do some changes now to the directory.  
  41. //Create a DirectoryInfo object.  
  42. DirectoryInfo d1 = new DirectoryInfo(args[0]);  
  43. //Create a new subdirectory.  
  44. d1.CreateSubdirectory("mydir");  
  45. //Create some subdirectories.  
  46. d1.CreateSubdirectory("mydir1\\mydir2\\mydir3");  
  47. //Move the subdirectory "mydir3 " to "mydir\mydir3"  
  48. Directory.Move(d1.FullName + "file://mydir1//mydir2//mydir3",  
  49. d1.FullName + "\\mydir\\mydir3");  
  50. //Check if subdirectory "mydir1" exists.  
  51. if (Directory.Exists(d1.FullName + "\\mydir1"))  
  52. {  
  53. //Delete the directory "mydir1"  
  54. //I have also passed 'true' to allow recursive deletion of  
  55. //any subdirectories or files in the directory "mydir1"  
  56. Directory.Delete(d1.FullName + "\\mydir1"true);  
  57. }  
  58. //Get an array of all directories in the given path.  
  59. DirectoryInfo[] d2 = d1.GetDirectories();  
  60. //Iterate over all directories in the d2 array.  
  61. foreach (DirectoryInfo d in d2)  
  62. {  
  63. if (d.Name == "mydir")  
  64. {  
  65. //If "mydir" directory is found then delete it recursively.  
  66. Directory.Delete(d.FullName, true);  
  67. }  
  68. }  
  69. // Wait for user to quit program.  
  70. Console.WriteLine("Press \'q\' to quit the sample.");  
  71. Console.WriteLine();  
  72. //Make an infinite loop till 'q' is pressed.  
  73. while (Console.Read() != 'q') ;  
  74. }  
  75. catch (IOException e)  
  76. {  
  77. Console.WriteLine("A Exception Occurred :" + e);  
  78. }  
  79. catch (Exception oe)  
  80. {  
  81. Console.WriteLine("An Exception Occurred :" + oe);  
  82. }  
  83. }  
  84. // Define the event handlers.  
  85. public static void OnChanged(object source, FileSystemEventArgs e)  
  86. {  
  87. // Specify what is done when a file is changed.  
  88. Console.WriteLine("{0}, with path {1} has been {2}", e.Name, e.FullPath, e.ChangeType);  
  89. }  
  90. public static void OnRenamed(object source, RenamedEventArgs e)  
  91. {  
  92. // Specify what is done when a file is renamed.  
  93. Console.WriteLine(" {0} renamed to {1}", e.OldFullPath, e.FullPath);  
  94. }  
  95. }  
The above code starts with the parameter obtained from the user in the form of a path to a directory. Then it creates a FileSystemWatcher instance to monitor all changes in files and directories. Once the FileSystemWatcher is enabled, we are ready to make some changes. In this example, a file and few directories are created and later deleted. Figure 2 contains the output displayed on the console screen.


Figure 2: Output of the FileWatcher class
As you can see, the FileSystemWatcher captured every change made. If you start Windows Explorer and browse the directory you have provided as the parameter, you will find that every change you make in Explorer is reflected in the console. Since input is obtained from the user, chances are high that invalid arguments could raise exceptions; therefore, all the file manipulation code is placed within the try-catch block.
Some Notes 
Here are some important notes when using the FileSystemWatcher class.
  • Hidden files are not ignored.
  • In some systems, FileSystemWatcher reports changes to files using the short 8.3 file name format. For example, a change to "LongFileName.LongExtension" could be reported as "LongFil~.Lon".
  • This class contains a link demand and an inheritance demand at the class level that applies to all members. A SecurityException is thrown when either the immediate caller or the derived class does not have full-trust permission. For details about security demands, see Link Demands.
  • The maximum size you can set for the InternalBufferSize property for monitoring a directory over the network is 64 KB.
IOException Class
The IOException class is the base class for exceptions under the System.IO namespace. All other exceptions under this namespace-DirectoryNotFoundException, EndOfStreamException, FileNotFoundException, and FileLoadException-derive from the IOException class. I/O operations deal with various resources like hard disk, floppy disk, and network sockets, which have a greater chance of failing. Therefore, you should always encapsulate your I/O code within the trycatch block to intercept any exceptions that might occur.
Hope this article have helped you in understanding FileSystemWatcher and IOException Class in C#.

Here are some more practical examples of FileSystemWatcher.