Wait for all files to be deleted using FileSystemWatcher - c#

I have a console app that need to monitor a specific directory and wait for all files to be deleted for a specific amount of time.
If after that time has exceeded and all of the files has not been deleted yet, I need the program to throw an exception. How can I accomplish this?
public static void FileWatcher(string fileName, int timeToWatch)
{
FileSystemWatcher watcher = new FileSystemWatcher();
try
{
watcher.Path = myPath;
watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName;
watcher.Filter = string.Format("*{0}*", fileName);
watcher.Deleted += new FileSystemEventHandler(OnChanged);
watcher.EnableRaisingEvents = true;
}
catch
{
throw;
}
}

You can use Task.Delay to setup a timeout (I assume timeToWatch is in milliseconds, if not then change it accordingly). If the directory has no more files (not checking subfolders) then it sets the other task as completed. The method will block (WaitAny) until either the timeout occurs or the files are all deleted. This can easily be changed to be async if required.
public static void FileWatcher(string fileName, int timeToWatch)
{
FileSystemWatcher watcher = new FileSystemWatcher();
var timeout = Task.Delay(timeToWatch);
var completedTcs = new TaskCompletionSource<bool>();
watcher.Path = myPath;
watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName;
watcher.Filter = string.Format("*{0}*", fileName);
watcher.Deleted += (s, e) => OnChanged(myPath, timeout, completedTcs);
watcher.EnableRaisingEvents = true;
OnChanged(myPath, timeout, completedTcs);
// Wait for either task to complete
var completed = Task.WaitAny(completedTcs.Task, timeout);
// Clean up
watcher.Dispose();
if (completed == 1)
{
// Timed out
throw new Exception("Files not deleted in time");
}
}
public static void OnChanged(string path, Task timeout, TaskCompletionSource<bool> completedTcs)
{
if (!Directory.GetFiles(path).Any())
{
// All files deleted (not recursive)
completedTcs.TrySetResult(true);
}
}

Related

Error 1053:The service did not respond to start or control request in timely fashion with FileSystemWatcher

I have created a Windows Service which uses a FileSystemWatcher to look for changes in different directories. When I launch the service I am getting the error:
Error 1053:The service did not respond to start or control request in timely fashion.
I think that the error is coming from an infinite loop caused by using the using statement in the Watch() method as shown below:
public FileSystemWatcher Watch()
{
FileSystemWatcher watcher;
using (watcher = new FileSystemWatcher($"C:\\Users\\lashi\\AppData\\Roaming\\Sublime Text 3", _ext))
{
watcher.NotifyFilter = NotifyFilters.LastAccess
| NotifyFilters.LastWrite
| NotifyFilters.FileName
| NotifyFilters.DirectoryName;
watcher.IncludeSubdirectories = true;
// Add event handlers.
watcher.Changed += OnChanged;
watcher.Created += OnChanged;
watcher.Deleted += OnChanged;
watcher.Renamed += OnRenamed;
// Begin watching.
watcher.EnableRaisingEvents = true;
}
return watcher;
}
This is my OnStart() method:
protected override void OnStart(string[] args)
{
String userName;
String expt;
if (args.Length < 2)
{
Console.WriteLine($"FileWatcher <user> <exptName>");
Console.WriteLine($"Captures files into /temp/<exptName>-log and /temp/<exptName>-files");
userName = "wost";
expt = "expt1";
}
else
{
userName = args[0];
expt = args[1];
}
String lexpt = $"C:\\Users\\lashi\\Desktop\\EMMC_CACHE\\{expt}-log";
String fexpt = $"C:\\Users\\lashi\\Desktop\\EMMC_CACHE\\{expt}-file";
if (!Directory.Exists(fexpt))
{
Directory.CreateDirectory(fexpt);
}
if (!Directory.Exists(lexpt))
{
Directory.CreateDirectory(lexpt);
}
// File Watcher Launch
Watcher w = new Watcher(lexpt, fexpt, userName);
FileSystemWatcher fw = w.Watch();
}
Can you please help me to find a solution to this issue? I have tried a lot of suggestions but they don't seem to work. Thank you!
Click here! to see how to increase Windows services pipe timeout by editing the registry keys

How to detect a file being removed from folder

I am trying to detect when a file is being removed from a folder in my drive. Upon detection, I want to write code that does something. Is there an event handler for this kind of 'event' in C#? Looked around but couldn't find any. Is it even possible?
You can use FileSystemWatcher to monitor a directory, and subscribe to it's Deleted event. See the code below
static void Main(string[] args)
{
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = "C:/some/directory/to/watch";
watcher.NotifyFilter = NotifyFilters.LastAccess |
NotifyFilters.LastWrite |
NotifyFilters.FileName |
NotifyFilters.DirectoryName;
watcher.Filter = "*.*";
watcher.Deleted += new FileSystemEventHandler(OnDeleted);
watcher.EnableRaisingEvents = true;
}
private static void OnDeleted(object sender, FileSystemEventArgs e)
{
throw new NotImplementedException();
}

filewatchersystem is not firing the events after sometime

Below is my code, I am running a windows service, but if i kept ideal for long time 5 or 6 days after that it stops firing events. though my service is running.Please help me on this
private FileSystemWatcher watcher = new FileSystemWatcher();
public bool StartFileWatcher()
{
_logger.Info("StartFileWatcher File watcher started");
if (string.IsNullOrEmpty(_fileWatcherTargetPath))
{
_logger.Error("StartFileWatcher Directory name is null or Empty");
return false;
}
DirectoryInfo dir = new DirectoryInfo(_fileWatcherTargetPath);
if (!Directory.Exists(_fileWatcherTargetPath))
{
_logger.Info("StartFileWatcher Directory Created " + _fileWatcherTargetPath);
Directory.CreateDirectory(_fileWatcherTargetPath);
}
//Add folder path to file watcher
watcher.Path = _fileWatcherTargetPath;
watcher.IncludeSubdirectories = true;
//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;
// Add event handlers.
watcher.Created += new FileSystemEventHandler(OnChanged);
// Begin watching.
watcher.EnableRaisingEvents = true;
GC.KeepAlive(watcher);
SetTimer();
return true;
}

Switch FileSystemWatcher on and off to avoid multiple instances

Newbee alert. Problem: I populate a combo box, user makes a selection. I then create and enable a FSW. All works well, until user revisits combo box to make an alternate selection. At that point, another FSW is instantiated resulting in IO Exceptions based on 'file in use' errors. I need to switch off the FSW (or destroy the instantiation) when the user makes a subsequent selection in the combo box. Entire program is driven from a Winform with the combo box.
How do either toggle the FSW on/off, or destroy the FSW instantiation and allow a new, similar one to be created when the user revisits the combo box and makes another selection?
Code that calls for instantiation of the FSW:
private void MinAndGo()
{
if (strLblPtr != null)
{
if(strLblPtr != "None")
{
if (!CheckMyPrinter(strLblPtr))
{
MessageBox.Show(ForegroundWindow.Instance, "Printer is not ready. Make sure it's turned on "
+ "and has paper loaded.", "Printer Not Ready");
}
}
this.WindowState = FormWindowState.Minimized;
this.Activate();
bCreateWatcher = true;
Watchit();
}
}
Code for WatchIt(). I was intending on using the bool bCreateWatcher to toggle the FSW on and off.
private static void Watchit()
{
List<string> list = new List<string>();
list.Add("C:\\SAMMS\\pcl");
list.Add("C:\\SAMMS\\lbl");
foreach (string my_path in list)
{
Watch(my_path);
}
}
private static void Watch(string watch_folder)
{
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.InternalBufferSize = 8192; //defaults to 4KB, need 8KB buffer
watcher.Path = watch_folder;
watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
| NotifyFilters.FileName | NotifyFilters.DirectoryName;
watcher.Filter = "*.*";
watcher.Created += new FileSystemEventHandler(OnCreated);
// Begin watching.
try
{
if (bCreateWatcher)
{
watcher.EnableRaisingEvents = true;
}
else
{
watcher.EnableRaisingEvents = false;
}
}
catch(Exception ex)
{
MessageBox.Show(ForegroundWindow.Instance, "FSW not set correctly" + ex, "FSW Error");
}
}
The FileSystemWatcher implements IDisposable. Therefore you should call Dispose to destroy the instance.
You can find more information here:
http://msdn.microsoft.com/en-us/library/system.io.filesystemwatcher.dispose(v=vs.80).aspx
http://msdn.microsoft.com/en-us/library/system.idisposable.aspx
Ok, so it looks like you need to store your watcher somewhere, perhaps a dictionary keyed on the path? You'll also need to have the class that this is all contained in implement IDisposable, so that you can properly call Dispose() on any watchers you currently have open with the class is disposed of. (You should then ensure that the containing class is also properly disposed.)
I would refactor Watch() to something like this (could probably be better):
private static IDictionary<string, FileSystemWatcher> _openWatchers
= new Dictionary<string, FileSystemWatcher>();
private static void Watch(string watch_folder)
{
if (!bCreateWatcher)
{
if (_openWatchers.ContainsKey(watch_folder))
{
_openWatchers[watch_folder].Dispose();
_openWatchers.Remove(watch_folder);
}
return;
}
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.InternalBufferSize = 8192; //defaults to 4KB, need 8KB buffer
watcher.Path = watch_folder;
watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
| NotifyFilters.FileName | NotifyFilters.DirectoryName;
watcher.Filter = "*.*";
watcher.Created += new FileSystemEventHandler(OnCreated);
// Begin watching.
try
{
watcher.EnableRaisingEvents = true;
_openWatchers[watch_folder] = watcher;
}
catch(Exception ex)
{
MessageBox.Show(ForegroundWindow.Instance, "FSW not set correctly" + ex, "FSW Error");
}
}
And your Dispose() method:
public void Dispose()
{
foreach (FileSystemWatcher fsw in _openWatchers.Values)
{
fsw.Dispose();
}
}

Filewatcher returning error. No overload matches delegate

I've written this method which should check for file changes.
public static void watch()
{
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = ConfigurationManager.AppSettings["OpticusFileLoc"];
watcher.Filter = "sigtrades.xml";
watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
| NotifyFilters.FileName | NotifyFilters.DirectoryName;
// watcher.Created += new FileSystemEventHandler(OnChanged);
watcher.Changed += new FileSystemEventHandler(OnChanged);
watcher.EnableRaisingEvents = true;
}
However, I get this error:
"No overload for 'OnChanged' matches delegate 'System.IO.SystemEventHandler'
Where am I going wrong?
Your OnChanged method needs to have the following signature:
void OnChanged(object sender, FileSystemEventArgs e);
Does it?

Categories

Resources