Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Smart Watcher

0.00/5 (No votes)
5 Sep 2013 1  
Easy to use directory watching tool.

Introduction  

Note: now Smartwatcher is hosted by CodePlex , you can download the code and check updates on

https://smartwatcher.codeplex.com/ 

Smart Watcher is a simple windows service designed to watch a specific directories and taking specific actions to : Create - Change - Rename - Delete files events into those directories. The advantage of this tool:

  • Supporting plugins, just code about you business (what you want to do with file) compile your code into dll and let Smart Watcher take care about files watching.
  • Check if file is used by another service and wait before processing it (very useful specially when you are working with large files when coping or downloading them).
  • Support multiple file extensions and filters.
  • Using Regular Expressions for files filtering. - Watch many directories at the same time.
  • Creating a queue if many files created at the same time.
  • Archive the files into password protected zip files in case of success or failure.

Using the tool  

To use Smart Watcher you just need to install the service and develop your plugins then add them to the plugin folder into service root. To install the service just double click on the service executable file ( thank you to Sudheer Reddy Battula for his article : Installing .NET Windows Services (the easiest way) ) before starting the service you should set the SuccessArchivePath and FailureArchivePath settings into exe config file, to tell the service were you want to archive a zipped copy of files after processing. Also the 'ReadTries' into settings determine how many time the service should try to access a file in case in it using by another service, you should increase this value in case you are downloading large files. To create you plugin create a new class library project and inherit your class from the IPlugin interface and handle the interface properties and methods.

string Name { get; set; }
string WatchPath { get; set; }
string Filter { get; set; }
bool CatchAllFiles { get; set; }
string ZipPassword { get; set; }
string FilePrefix { get; set; }
IPluginHost Host { get; set; }
bool ArchiveFiles { get; set; }
bool DeleteFiles { get; set; }

/// <summary>
/// Event occurs when the a File or Directory is created
/// </summary>
/// <param name="fileName">The file full path name</param>
/// <returns></returns>
bool FileCreated(string fileName);
/// <summary>
/// Event occurs when the contents of a File or Directory are changed
/// </summary>
/// <param name="fileName">The file full path name</param>
/// <returns></returns>
bool FileChanged(string fileName);
/// <summary>
/// Event occurs when the a File or Directory is deleted
/// </summary>
/// <param name="fileName">The file full path name</param>
/// <returns></returns>
bool FileDeleted(string fileName);
/// <summary>
/// Event occurs when the a File or Directory is renamed
/// </summary>
/// <param name="fileName">The file full path name</param>
/// <returns></returns>
bool FileRenamed(string fileName); 

Name : the name of you plugin.
WatchPath : the path of the directory where you want the service to watch.
Filter: filter string used to determine what files are monitored in a directory.
ZipPassword : the password of the zip file created for archiving.
FilePrefix : a prefix added to the name of zipped files for archiving.
ArchiveFiles : if True Let the service to archive files by zipping and saving them into specific folders.
DeleteFiles : if True delete the file after finishing.
compile your library after that take the assembly file and change its extension from 'dll' to '.plug'
copy the assembly to the 'Plugin' folder into Smart Watcher bin folder
finally start the service.

Deeper Look  

By installing the service and writing your plugins you just scratch the surface, Let 's take deeper look about
how Smart Watcher is working, first of all let me redefine Smart Watcher for you with another words :
Smart Watch is a windows service which encapsulate FileSystemWatcher class, it is plug able service so you
can write your plugins and each plugin could be associated to watch a specific folder with specific file filter.
with every plugin you add, Smart Watcher automatically will create an FileSystemWatcher instance and add it to the service watchers list, The service will responsible about every thing else , it is include build in queue system to avoid any problem happen when many files created or changed at the same time, also it will check if file available and not used by another application before sending it to the appropriate plugin.

Variables

#region Variables
// Failur archive folder path from service setting
public static string SettingsFailureArchivePath = Properties.Settings.Default.FailureArchivePath;
// Success archive folder path from service setting
public static string SettingsSuccessArchivePath = Properties.Settings.Default.SuccessArchivePath;
// How many tries to access the file in case it used by another service
public static int SettingsReadTries = Properties.Settings.Default.ReadTries;
// the extention of zipped archived files
public static string SettingsZipFileExtention = "zip";
// the path of plugin folder (where the Smart Watcher will look for its plugins)
private readonly string _PluginFolder = AppDomain.CurrentDomain.BaseDirectory + @"Plugin\";

// a list of the avilable plugins into Plugin folder
public static IPlugin[] ipi;

// List of file watchers (the Smart Watcher create one for each plugin)
private List<FileSystemWatcher> _lstWatchers = new List<FileSystemWatcher>();

// FileProcessor is the class which maintains a queue of files to be processed and controls a worker thread which processes each file in the queue.
static FileProcessor processor;

#endregion  

Methods:  

#region Methods

// this function is responsible a about looking for plugins
// into Plugin folder and add them the Smart Wacher plugins list (ipi)
private void LoadPlugIns()

// After Smart Watcher detect its plugins it call this function to create
// a SystemFileWatcher for each plugin and initialize it with plugin sttings.
private void RegisterWatchers()

#endregion

Constructor

In the service constructor we first create a new instance of FileProcessor class to maintain files queue, then we call LoadPlugin method to check available plugins then we call RegisterWatchers function to create watchers list.

Note: the line System.Diagnostics.Debugger.Launch(); is to debug the service, for more details please check this URL

public SmartWatcherService()
{
    InitializeComponent();

    #if DEBUG
        System.Diagnostics.Debugger.Launch();
    #endif

        // intilaize files processor to maintains files queue 
        processor = new FileProcessor();

        LoadPlugIns();
        RegisterWatchers();
}

Events:

There is four main file events into the service:

  • fswWatcher_Changed : Event occurs when the contents of a File or Directory are changed
  • fswWatcher_Created : Event occurs when the a File or Directory is created
  • fswWatcher_Deleted : Event occurs when the a File or Directory is deleted
  • fswWatcher_Renamed : Event occurs when the a File or Directory is renamed.

Each one of these events when fired calls the function processor.QueueInput(e.FullPath, e.ChangeType); where "e.FullPath" is the file name and e.ChangeType is the type of event , the QueueInput function add the file to a queue and it wait its turn for processing, when the file is ready two important functions are called .

private void ProcessFile(string fileInfo)
{
    string[] file = fileInfo.Split('|');
    WatcherChangeTypes changeType;
    WatcherChangeTypes.TryParse(file[0], true, out changeType);
    string filepath = file[1];
    

    if (!File.Exists(filepath))
    {
        //ToDo: Add Handle Exception
        return;
    }

    // Check if file is accessble
    if (!WaitReady(filepath, SmartWatcherService.SettingsReadTries))
    {
        //ToDo: Add Log
        return;
    }

    foreach (IPlugin t in SmartWatcherService.ipi)
    {
        string strFiletr = t.Filter.Replace("*", @"\\*");
        Match match = Regex.Match(Path.GetFileName(filepath), strFiletr);
        if (match.Success == true)
        {
            Func<string, bool> pluginFunc = null;
            switch (changeType)
            {
                    case WatcherChangeTypes.Created:
                    {
                        pluginFunc = t.FileCreated;
                        break;
                    }
                    case WatcherChangeTypes.Changed:
                    {
                        pluginFunc = t.FileChanged;
                        break;
                    }
                    case WatcherChangeTypes.Renamed:
                    {
                        pluginFunc = t.FileRenamed;
                        break;
                    }
                    case WatcherChangeTypes.Deleted:
                    {
                        pluginFunc = t.FileDeleted;
                        break;
                    }
            }

            ProcessPluginAction(pluginFunc, filepath, t.ArchiveFiles, t.DeleteFiles, t.FilePrefix,
                                t.ZipPassword);
        }
    }
}  

the ProcessFile function look for which plugin has filter apply with this file using Regex which (so more than one plugin can process the file if the filter is apply) and for each apply it call the "ProcessPluginAction" function.

private void ProcessPluginAction(Func<string, bool> pluginMethod, string fileFullName, bool archiveFiles, bool deleteFiles, string filePrefix, string zipPassword)
{

    string strArchivePath = SmartWatcherService.SettingsFailureArchivePath;
    try
    {
        pluginMethod(fileFullName);
        strArchivePath = SmartWatcherService.SettingsSuccessArchivePath;

    }
    catch (Exception ex)
    {
        //ToDo: add exception handeling                  
    }
    finally
    {
        if (archiveFiles == true)
        {
            string strArchiveFileName = filePrefix + "_" + DateTime.Now.ToString("yyyyMMddHHmmssss") + "_" +
                                        Path.GetFileName(fileFullName) + "." + SmartWatcherService.SettingsZipFileExtention;
            ZipUtil.ZipFile(fileFullName, strArchivePath + strArchiveFileName, zipPassword);
        }
        if (deleteFiles == true)
        {
            if (File.Exists(fileFullName))
            {
                // Check if file is accessble
                if (FileProcessor.WaitReady(fileFullName, SmartWatcherService.SettingsReadTries) == true)
                {
                    File.Delete(fileFullName);
                }
            }
        }
    }

}  

The ProcessPluginAction function accept delegate Func parameter represent the method should be called from the plugin and the file name will pass to this method , also the other parameters work like flags for archiving (zipping) files or delete them after finish. 

Points of Interest  

Smart Watcher is an easy to use tool help you to automate a lot of tasks, it is able to be extended by developing many plugins to do various kinds of actions like : sending mails, printing documents, transferring files , Start programs , ..
I can compare it to some commercial solutions like :WatchDirectory
For files zipping I am using the open source library : SharpZipLib 

History   

2013/1/13 Initial Release 0.1 

2013/08/06 Project added to CodePlex as SmartWatcher

2013/09/05 SmartWatcher 1.3.0.0 has been released, You can check release notes and get its source code from here: SmartWatcher 1.3.0.0 

Release Notes:

- Add: Introducing SmartTimer: a feature which implements a timer that raises an event at user-defined intervals. Now SmartWatcher support the Tick event
which regularly invokes code. Every several seconds or minutes, Just handle this event in your plugin and SmartWatcher will invoke your code.

- Add: Introducing SmartActions: a library will include code snippets and function so you can use them directly into SmartWatcher plugins.

- Add: PluginsLibrary folder to SmartWatcher project to add future plugins. 

 

 

 

 

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here