using System; using System.Collections.Generic; using System.Linq; using System.Threading; namespace JD.Core { public delegate void FilesChangedDelegate(IEnumerable changedFiles); /// /// A light implementation of a file watcher, meant to watch safely a limited number of files. /// public class FileWatcherLight : IDisposable { private List _watchedFiles = new List(); private readonly Timer _watchTimer; private readonly Mutex _watchMutex; private bool _enabled; public FileWatcherLight() { _watchMutex = new Mutex(); _watchTimer = new Timer(OnWatchTimerElapsed, null, Timeout.Infinite, Timeout.Infinite); _enabled = false; } ~FileWatcherLight() { Dispose(false); } public event FilesChangedDelegate FilesChanged; public bool Enabled { get { return _enabled; } set { _enabled = value; _watchTimer.Change(_enabled ? 1000 : Timeout.Infinite, Timeout.Infinite); } } public void WatchFile(string filePath, string parentFilePath = null) { _watchMutex.WaitOne(); var fileInfo = new System.IO.FileInfo(filePath); _watchedFiles.Add(new File(filePath, fileInfo.LastWriteTime, parentFilePath)); _watchMutex.ReleaseMutex(); } public void UnwatchFile(string filePath) { _watchMutex.WaitOne(); _watchedFiles = _watchedFiles.Where(file => file.Path != filePath && file.ParentPath != filePath).ToList(); _watchMutex.ReleaseMutex(); } private void OnWatchTimerElapsed(object dummy) { if (FilesChanged != null) { _watchMutex.WaitOne(); var changedFiles = new List(); foreach (var file in _watchedFiles) { var fileInfo = new System.IO.FileInfo(file.Path); if (file.Update(fileInfo.LastWriteTime)) { changedFiles.Add(String.IsNullOrEmpty(file.ParentPath) ? file.Path : file.ParentPath); } } if (changedFiles.Any()) FilesChanged(changedFiles); _watchMutex.ReleaseMutex(); } _watchTimer.Change(1000, Timeout.Infinite); } private class File { private DateTime _modifiedTime; public File(string path, DateTime modifiedTime, string parentPath = null) { Path = path; _modifiedTime = modifiedTime; ParentPath = parentPath; } public string Path { get; } public string ParentPath { get; } public bool Update(DateTime lastWriteTime) { if (_modifiedTime.Equals(lastWriteTime)) return false; _modifiedTime = lastWriteTime; return true; } } private void Dispose(bool disposing) { if (disposing) { _watchTimer?.Dispose(); _watchMutex?.Dispose(); } } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } } }