myoddweb.directorywatcher
                                
                                
                                
                                    myoddweb.directorywatcher copied to clipboard
                            
                            
                            
                        A fast and reliable, (non blocking!), .NET/C++ File/Directory watcher, complete rewrite of FileSystemWatcher to ensure speed/accuracy/reliability/suppress duplicate events.
Myoddweb.Directorywatcher 
A fast and reliable File/Directory watcher for c#/c++ to replace the current .NET FileSystemWatcher class.
What it does
- Reliable monitoring of
- Renamed files/directories
 - Deleted files/directories
 - Created files/directories
 
 - All exceptions are passed back to the caller.
 - Non-blocking delegates, if one function takes a long time ... we don't all have to suffer.
 - The interface does allow for porting to other platforms.
 - No buffer limitations, (well there is, but we play nicely).
 - Try and remove duplicates, (where possible).
 - Deleted, (then re-created), are re-monitored.
 - Watcher statistics
 
What it doesn't do
- Bring me coffee.
 
Installing
Nuget
Package manager
Install-Package MyOddWeb.DirectoryWatcher
CLI
.NET
dotnet add package MyOddWeb.DirectoryWatcher
Packet
paket add MyOddWeb.DirectoryWatcher
Use case
My needs were to, reliably, monitor entire volumes for created/deleted/renamed files. I do really care for pattern matching.
The issue(s) with FileSystemWatcher
The current version of File Watcher is great, but it does have a couple of issues.
- There is a buffer limitation, (in the API itself), and a badly written application can 'block' or 'miss' certain notification.
 - Duplicates are often sent, (when a file is updated 3 times between calls, we only need to know about the once).
 - Certain Exceptions cause the entire app to close.
 - UNC/Unix files are not supported, (in fact it causes 
FileSystemWatcherto take your system down). - Does not handle large volumes nicely.
 
Examples
Simple Watch
Add all the directories we want to 'observe'
    using( var watch = new Watcher() )
    {
      watch.Add(new Request("c:\\", true));
      watch.Add(new Request("d:\\foo\\bar\\", true));
      watch.Add(new Request("y:\\", true));
      // do something amazing with the data
      watch.OnAddedAsync += async (f, t) =>
      {
        // ..
      };
      // start watching
      watch.Start();
      // add some more
       watch.Add(new Request("z:\\", false));
      // optional stop in this case
      watch.Stop();
    }
You can start watching at any point
    // create Watcher
    var watcher = new Watcher();
    // Add a request.
    watch.Add(new Request("y:\\", true));
    // start watching
    watch.Start();
    // add some more
    watch.Add(new Request("z:\\", false));
Get notifications in case a file is created.
    watch.OnAddedAsync += async (f, t) =>
    {
      Console.ForegroundColor = ConsoleColor.Green;
      Console.WriteLine(
        $"[{f.DateTimeUtc.Hour}:{f.DateTimeUtc.Minute}:{f.DateTimeUtc.Second}]:{f.FileSystemInfo}");
      Console.ForegroundColor = foreground;
    };
we get given the file that was added as well as a cancellation token
And when we are done stop it ...
    watch.Stop();
Or Dispose of it
    watch.Dispose();
Your own 'Watcher' interface
You can create your own watcher interface
public class Watcher : IWatcher3
{
  // Implement IWatcher3
}
Watched Events
When a file event is raised we send a IFileSystemEvent event.
    /// <summary>
    /// The file system event.
    /// </summary>
    FileSystemInfo FileSystemInfo { get; }
    /// <summary>
    ///  Gets the full path of the directory or file.
    /// </summary>
    /// <returns>A string containing the full path.</returns>
    string FullName { get; }
    /// <summary>
    ///     For files, gets the name of the file. For directories, gets the name of the last
    ///     directory in the hierarchy if a hierarchy exists. Otherwise, the Name property
    ///     gets the name of the directory.
    /// </summary>
    /// <returns>A string that is the name of the parent directory, the name of the last directory
    ///     in the hierarchy, or the name of a file, including the file name extension.
    /// </returns>
    string Name { get; }
    /// <summary>
    /// The Action
    ///  Added
    ///  Removed
    ///  Touched
    ///  Renamed
    /// </summary>
    EventAction Action { get; }
    /// <summary>
    /// An error code related to the event, (if any)
    /// </summary>
    EventError Error { get; }
    /// <summary>
    /// The UTC date time of the event.
    /// </summary>
    DateTime DateTimeUtc { get; }
    /// <summary>
    /// Boolean if the update is a file or a directory.
    /// </summary>
    bool IsFile { get; }
    /// <summary>
    /// Return if the event is a certain action
    /// (same as Action == action)
    /// </summary>
    /// <param name="action"></param>
    /// <returns></returns>
    bool Is(EventAction action );
Statistics
You can get statistics at various intervals for the events being watched.
All you need to do is add Rates to your watchers
    using( var watch = new Watcher() )
    {
      // watch the folder with stats every 10000 ms
      // a value of 0, (default), turns it off.
      watch.Add(new Request("c:\\", true, new Rates(10000, 50 )));
      // do something amazing with the statistics
      // the values is `IStatistics` with a cancellation token
      watch.OnStatisticsAsync += async (s, t) =>
      {
        // ..
      };
      // start watching
      watch.Start();
      // ... do some clever stuff.
      // optional stop in this case
      watch.Stop();
    }
Logger
You can watch for certain events
Unknown= 0, Should never happenInformation= 1, nothing important, maybe something worth notingWarning= 2, something happened, but we managed to recover from itError= 3, something broke, messages were probably lost.Panic= 4, something really bad happened, the process probably died.Debug= 100, Should not happen in release more, only for information
    using( var watch = new Watcher() )
    {
      // watch the folder with stats every 10000 ms
      // a value of 0, (default), turns it off.
      watch.Add(new Request("c:\\", true ));
      // do something amazing with the message
      // the values is `ILoggerEvent` with a cancellation token
      watch.OnLoggerAsync += async (e, t) =>
      {
        // ..
      };
      // start watching
      watch.Start();
      // ... do some clever stuff.
      // optional stop in this case
      watch.Stop();
    }