An Alternative Solution of FileSystemWatcher

Download EaseFilter File Monitor Filter Driver SDK Setup File
Download EaseFilter File Monitor Filter Driver SDK Zip File
Understand EaseFilter Filter Driver SDK Programming

Monitoring File Change using FileSystemWatcher in C#

FileSystemWatcher is a very powerful component, which allows us to connect to the directories and watch for specific changes within them, such as creation of new files, addition of subdirectories and renaming of files or subdirectories. This makes it possible to easily detect when certain files or directories are created, modified or deleted. It is one of the members of System.IO namespace.

Use FileSystemWatcher to watch for changes in a specified directory. You can watch for changes in files and subdirectories of the specified directory. You can create a component to watch files on a local computer, a network drive, or a remote computer.

To watch for changes in all files, set the Filter property to an empty string ("") or use wildcards ("*.*"). To watch a specific file, set the Filter property to the file name. For example, to watch for changes in the file MyDoc.txt, set the Filter property to "MyDoc.txt". You can also watch for changes in a certain type of file. For example, to watch for changes in text files, set the Filter property to "*.txt".

There are several types of changes you can watch for in a directory or file. For example, you can watch for changes in Attributes, the LastWrite date and time, or the Size of files or directories. This is done by setting the NotifyFilter property to one of the NotifyFilters values. For more information on the type of changes you can watch, see NotifyFilters.

You can watch for renaming, deletion, or creation of files or directories. For example, to watch for renaming of text files, set the Filter property to "*.txt" and call the WaitForChanged method with a Renamed specified for its parameter.

You specify the type of change to watch for by setting the value of a WatcherChangeType enumeration. The possible values are as follows:

Member Name Description
All    The creation, deletion, change, or renaming of a file or folder.
Changed    The change of a file or folder. The types of changes include: changes to size, attributes, security settings, last write, and last access time.
Created  The creation of a file or folder.
Deleted The deletion of a file or folder.
Renamed The renaming of a file or folder.

WaitForChanged is a synchronous method that returns an object of type WaitForChangedResult. This class contain specific information on the type of change that occurred in the directory. You can access information such as Name, OldName, and TimedOut on this object to find out more about the change. TimeOut is the time (in milliseconds) to wait before timing out.

The Windows operating system notifies your component of file changes in a buffer created by the FileSystemWatcher. If there are many changes in a short time, the buffer can overflow. This causes the component to lose track of changes in the directory, and it will only provide blanket notification. Increasing the size of the buffer with the InternalBufferSize property is expensive, as it comes from non-paged memory that cannot be swapped out to disk, so keep the buffer as small yet large enough to not miss any file change events. To avoid a buffer overflow, use the NotifyFilter and IncludeSubdirectories properties so you can filter out unwanted change notifications.

FileSystemWatcher Examples

The following example creates a FileSystemWatcher to watch the directory specified at run time. The component is set to watch for changes in LastWrite and LastAccess time, the creation, deletion, or renaming of text files in the directory. If a file is changed, created, or deleted, the path to the file prints to the console. When a file is renamed, the old and new paths print to the console.

 
  
using System;
using System.IO;
using System.Security.Permissions;

public class Watcher
{
    public static void Main()
    {
        Run();
    }

    [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
    private static void Run()
    {
        string[] args = Environment.GetCommandLineArgs();

        // If a directory is not specified, exit program.
        if (args.Length != 2)
        {
            // Display the proper way to call the program.
            Console.WriteLine("Usage: Watcher.exe (directory)");
            return;
        }

        // Create a new FileSystemWatcher and set its properties.
        using (FileSystemWatcher watcher = new FileSystemWatcher())
        {
            watcher.Path = args[1];

            // Watch for changes in LastAccess and LastWrite times, and
            // the renaming of files or directories.
            watcher.NotifyFilter = NotifyFilters.LastAccess
                                 | NotifyFilters.LastWrite
                                 | NotifyFilters.FileName
                                 | NotifyFilters.DirectoryName;

            // Only watch text files.
            watcher.Filter = "*.txt";

            // Add event handlers.
            watcher.Changed += OnChanged;
            watcher.Created += OnChanged;
            watcher.Deleted += OnChanged;
            watcher.Renamed += OnRenamed;

            // Begin watching.
            watcher.EnableRaisingEvents = true;

            // Wait for the user to quit the program.
            Console.WriteLine("Press 'q' to quit the sample.");
            while (Console.Read() != 'q') ;
        }
    }

    // Define the event handlers.
    private static void OnChanged(object source, FileSystemEventArgs e) =>
        // Specify what is done when a file is changed, created, or deleted.
        Console.WriteLine($"File: {e.FullPath} {e.ChangeType}");

    private static void OnRenamed(object source, RenamedEventArgs e) =>
        // Specify what is done when a file is renamed.
        Console.WriteLine($"File: {e.OldFullPath} renamed to {e.FullPath}");
}

  

Monitoring File IO Activities using EaseFilter FileMonitor SDK in C#

EaseFilter file system filter driver monitor SDK can monitor the file change, file creation, file rename or file deletion for the specific folder, EaseFilter FileMonitor SDK not only has the same file change type as FileSystemWatcher, but also has more file event types than FileSystemWatcher, there are more categories for the file change: file was written, file security was changed, file information was changed.

 
/// The events which happened between the file opens and file closes, it will be fired after the file handle was closed.
public enum MonitorFileEvents
{
	/// Fires this event when the new file was created after the file handle closed
	NotifyFileWasCreated = 0x00000020,
	/// Fires this event when the file was written after the file handle closed
	NotifyFileWasWritten = 0x00000040,
	/// Fires this event when the file was moved or renamed after the file handle closed
	NotifyFileWasRenamed = 0x00000080,
	/// Fires this event when the file was deleted after the file handle closed
	NotifyFileWasDeleted = 0x00000100,
	/// Fires this event when the file's security was changed after the file handle closed
	NotifyFileSecurityWasChanged = 0x00000200,
	/// Fires this event when the file's information was changed after the file handle closed
	NotifyFileInfoWasChanged = 0x00000400,
	/// Fires this event when the file's data was read after the file handle closed
	NotifyFileWasRead = 0x00000800,
}
 

The features EaseFilter FileMonitor SDK has, but FileSystemWatcher doesn't have

  1. Track who changed the file in the folder with the requestor's user name and process name of the file event.

  2. The EaseFilter FileMonitor SDK can provide the user name and process name for every callback file Io. You will know who ( user name and process name) accessed your files when the file was accessed or changed in real time. If the file was accessed by network share, the EaseFilter file monitor also can provide the remote IP address.

  3. The file IO information

  4. The EaseFilter FileMonitor SDK not only provides the file name, but also provides the file size, file attributes, file time information in the callback event.

  5. The file IO activities.

  • The file open or file create IO
  • Reference CreateFile or FltCreateFile API, you will know how the file was opened. In the file open/create callback event, you will know the file open option "DesiredAccess","CreateOption", "Disposition". You will know the status of the file open: if the status is succeeded, you will know that the file was opened or created sucessfully, if the file open is failed, you will know the reason of the file open failure.

  • The read file IO
  • Reference ReadFile or FltReadFile API, you will know how the file was read. In the file read callback event, you will know the read offset, read length information, if the read succeeded, you will get the read data.

  • The write file IO
  • Reference WriteFile or FltWriteFile API, you will know how the file was written. In the file write callback event, you will know the write offset, write lenght information, written data to the file.

  • The file rename IO
  • Reference MoveFile API, you will get the file rename callback event with the new file name, the requestor's user name and processname

  • The delete file IO
  • Reference DeleteFile API, you will get the file delete callback event with the file information, the requestor's user name and process name.

  • The get file size or set file size IO
  • Reference GetFileSize, SetEndOfFile API, you will get the file size information if the file size query was succeeded, you will know the file size was set for the set file size IO.

  • The query or set file attribue, file last access time, file last write time, file creation time IO
  • Reference GetFileAttributes, SetFileAttributes, GetFileTime and SetFileTime API, you will get the file attributes and file time information with the callback event.

  • The query or set file security IO
  • Reference GetSecurityInfo, SetSecurityInfo API, you will the file security descriptor was queried or set in the callback event.

  • The directory file list IO
  • Reference FindFirstFile and FindNextFile API, you will get the file list of the directory in the callback event.

  • The file handle close IO
  • Reference CloseHandle API, you will get the file information in the file handle close callback event.

EaseFilter File Monitor Examples

The following example creates a filter rule to watch the directory specified at run time. The component is set to watch for all file change in the directory. If a file was changed, the file name, file change type, user name, process name will be printed to the console. The component also is set to watch the file open and file read IO, the IO was triggered, the file open and file read information will be printed to the console.

 
  
using System;
using EaseFilter.FilterControl;

namespace FileMonitorConsole
{
    class Program
    {
        static FilterControl filterControl = new FilterControl();

        static void Main(string[] args)
        {
            string lastError = string.Empty;
            string licenseKey = "Email us to request a trial key: info@easefilter.com";
                
            FilterAPI.FilterType filterType = FilterAPI.FilterType.MONITOR_FILTER;
            int serviceThreads = 5;
            int connectionTimeOut = 10; //seconds

            try
            {
                if (!filterControl.StartFilter(filterType, serviceThreads, connectionTimeOut, licenseKey, ref lastError))
                {
                    Console.WriteLine("Start Filter Service failed with error:" + lastError);
                    return;
                }

                //the watch path can use wildcard to be the file path filter mask.i.e. '*.txt' only monitor text file.
                string watchPath = "c:\\test\\*";

                if (args.Length > 0)
                {
                    watchPath = args[0];
                }

                //create a file monitor filter rule, every filter rule must have the unique watch path. 
                FileFilter fileMonitorFilter = new FileFilter(watchPath);

                //Filter the file change event to monitor all file change events.
                fileMonitorFilter.FileChangeEventFilter = FilterAPI.MonitorFileEvents.NotifyAll;

                //register the file change callback events.
                fileMonitorFilter.NotifyFileWasChanged += NotifyFileChanged;

                //Filter the monitor file IO events
                fileMonitorFilter.MonitorFileIOEventFilter = (ulong)(MonitorFileIOEvents.OnFileOpen | MonitorFileIOEvents.OnFileRead);

                fileMonitorFilter.OnFileOpen += OnFileOpen;
                fileMonitorFilter.OnFileRead += OnFileRead;

                filterControl.AddFilter(fileMonitorFilter);

                if (!filterControl.SendConfigSettingsToFilter(ref lastError))
                {
                    Console.WriteLine("SendConfigSettingsToFilter failed." + lastError);
                    return;
                }

                Console.WriteLine("Start filter service succeeded.");

                // Wait for the user to quit the program.
                Console.WriteLine("Press 'q' to quit the sample.");
                while (Console.Read() != 'q') ;

                filterControl.StopFilter();

            }
            catch (Exception ex)
            {
                Console.WriteLine("Start filter service failed with error:" + ex.Message);
            }

        }

        /// Fires this event when the file was changed.
        static void NotifyFileChanged(object sender, FileChangeEventArgs e)
        {
            Console.WriteLine("NotifyFileChanged:" + e.FileName + ",eventType:" + e.eventType.ToString() 
				+ ",userName:" + e.UserName + ",processName:" + e.ProcessName);
        }

        /// Fires this event after the file was opened, the handle is not closed. 
        static void OnFileOpen(object sender, FileCreateEventArgs e)
        {
            Console.WriteLine("FileOpen:" + e.FileName + ",status:" +  e.IOStatusToString() 
				+ ",userName:" + e.UserName + ",processName:" + e.ProcessName);
        }

        /// Fires this event after the read IO was returned.
        static void OnFileRead(object sender, FileReadEventArgs e)
        {
            Console.WriteLine("FileRead:" + e.FileName + ",offset:" + e.offset + ",readLength:" 
				+ e.returnReadLength + ",userName:" + e.UserName + ",processName:" + e.ProcessName);
        }
    }
}