Let's Synchronize Some FilesRecently, I posted about the new addition to my backup strategy; a NAS. My intended use of this device is to have a hot backup of my files. The system I was using before was not capable of storing the amount of data I need backed up, nor was it easy to manage.
I modified the set of xCopy batch files that I used for my backups to write the files to the NAS.
This system worked fine, but I needed more. I manage a lot of data and have a lot of files. I wouldn't want to lose any in the event of a system failure. The one problem I see with using this process is the lack of a real time solution.
I was in search of a solution that would offer me real-time synchronization between my files and the NAS. I didn't have to search very far. The .NET Framework includes the FileSystemWatcher Class.
The FileSystemWatcher Class "Listens to the file system change notifications and raises events when a directory, or file in a directory, changes." (quoted directly from MSDN) After reading through this class I quickly whipped up a solution. I developed my own FileSync class that allowed me to easily synchronize files between my remote and local storage. I created a Windows Service (threaded) built around my class (the screen shot in this post is from a sample app I used to test my class) so that I could have the FileSync class running and keeping my files in sync without me needing to do anything. Here is the unit I created:
using System;
using System.IO;
using System.Diagnostics;
namespace BPSoftware
...{
class FileSync
...{
private FileSystemWatcher watcher;

Fields#region Fields
private string destpath;
public string DestPath
...{
get ...{ return destpath; }
set ...{ destpath = value; }
}
private string sourcepath;
public string SourcePath
...{
get ...{ return sourcepath; }
set ...{ sourcepath = value; }
}
private string filter;
public string Filter
...{
get ...{ return filter; }
set ...{ filter = value; }
}
private bool watchsubfolders;
public bool WatchSubFolders
...{
get ...{ return watchsubfolders; }
set ...{ watchsubfolders = value; }
}
#endregion

Constructors#region Constructors
public FileSync()
...{
this.watcher = new FileSystemWatcher();
this.watcher.InternalBufferSize = 0x20000;
this.watcher.NotifyFilter = NotifyFilters.FileNameNotifyFilters.LastWrite;
this.watcher.IncludeSubdirectories = false;
this.watcher.Changed += new FileSystemEventHandler(this.OnChanged);
this.watcher.Created += new FileSystemEventHandler(this.OnCreated);
this.watcher.Deleted += new FileSystemEventHandler(this.OnDeleted);
this.watcher.Renamed += new RenamedEventHandler(this.OnRenamed);
}
public FileSync(string source, string destination, string filefilter, bool watchsubs): this()
...{
this.SourcePath = source;
this.DestPath = destination;
this.Filter = filefilter;
this.WatchSubFolders = watchsubs;
}
#endregion

Methods#region Methods
private string GetDestinationFile(string infile)
...{
string fileName = Path.GetFileName(infile);
return (this.destpath + fileName);
}
private void LogEvent(string message, int id)
...{
EventLog.WriteEntry("FileSync", message, EventLogEntryType.Error, id);
}
public void Start()
...{
try
...{
if (this.watcher != null)
...{
this.watcher.Path = this.SourcePath;
this.watcher.Filter = this.Filter;
this.watcher.IncludeSubdirectories = this.WatchSubFolders;
this.watcher.Filter = this.Filter;
this.watcher.EnableRaisingEvents = true;
}
}
catch (Exception exception)
...{
this.LogEvent(exception.Message, 0x01);
}
}
public bool Stop()
...{
try
...{
if (this.watcher != null)
...{
this.watcher.EnableRaisingEvents = false;
this.watcher.Changed -= new FileSystemEventHandler(this.OnChanged);
this.watcher.Created -= new FileSystemEventHandler(this.OnCreated);
this.watcher.Deleted -= new FileSystemEventHandler(this.OnDeleted);
this.watcher.Renamed -= new RenamedEventHandler(this.OnRenamed);
}
}
catch (Exception exception)
...{
this.LogEvent(exception.Message, 0x02);
return false;
}
return true;
}
#endregion

Events#region Events
private void OnChanged(object source, FileSystemEventArgs e)
...{
try
...{
File.Copy(e.FullPath, this.GetDestinationFile(e.FullPath), true);
}
catch (Exception exception)
...{
this.LogEvent(exception.Message, 0x03);
}
}
private void OnCreated(object source, FileSystemEventArgs e)
...{
try
...{
File.Copy(e.FullPath, this.GetDestinationFile(e.FullPath));
}
catch (Exception exception)
...{
this.LogEvent(exception.Message, 0x04);
}
}
private void OnDeleted(object source, FileSystemEventArgs e)
...{
try
...{
File.Delete(this.GetDestinationFile(e.FullPath));
}
catch (Exception exception)
...{
this.LogEvent(exception.Message, 0x05);
}
}
private void OnRenamed(object source, RenamedEventArgs e)
...{
try
...{
File.Move(this.GetDestinationFile(e.OldFullPath), this.GetDestinationFile(e.FullPath));
}
catch (Exception exception)
...{
this.LogEvent(exception.Message, 0x06);
}
}
#endregion
}
}