Switch FileSystemWatcher on and off to avoid multiple instances - c#

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();
}
}

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();
}

Wait for all files to be deleted using FileSystemWatcher

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);
}
}

Proper way to Implement a FileWatcher in a multithreading program C#

I have a multi-threaded program (3-4 threads). All the threads depend on a couple of parameters which are specified in an XML file.
Since the parameters in the XML file may be changed at any time by a user therefore, the different threads need to be notified about it and need to get the updated copy of parameters.
To monitor the changes in the XML file, I am using a FileWatcher as per the MSDN documentation.
clas ReadXML
{
//parameters
private static string Param1 = "";
private static string Param2 = "";
public static void ReadXmlParameters()
{
XmlDocument xDoc = new XmlDocument();
try
{
xDoc.Load(_ParameterFileDirrectory + #"\" + _ParameterFileDirrectory);
//parameters
Param1 = (xDoc.DocumentElement.SelectSingleNode("/Parameters/SetOne/IpAddress")).InnerText;
Param2 = (xDoc.DocumentElement.SelectSingleNode("/Parameters/SetOne/Username")).InnerText;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public static void CreateXMLWatcher()
{
try
{
// Create a new FileSystemWatcher and set its properties.
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = _ParameterFileDirrectory;
/* 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;
// Only watch .xml files.
watcher.Filter = _ParameterFileFilename; // "ParameterFile.xml";
// Add event handlers.
watcher.Changed += new FileSystemEventHandler(OnChanged);
watcher.Created += new FileSystemEventHandler(OnChanged);
watcher.Deleted += new FileSystemEventHandler(OnChanged);
watcher.Renamed += new RenamedEventHandler(OnRenamed);
// Begin watching.
watcher.EnableRaisingEvents = true;
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
}
// Define the event handlers.
private static void OnChanged(object source, FileSystemEventArgs e)
{
// Specify what is done when a file is "Changed", "Created", or "Deleted".
Console.WriteLine("File: " + e.FullPath + " " + e.ChangeType);
if (e.ChangeType.ToString() == "Changed")
{
ReadXmlParameters(); //Read the Parameters from XML again
MyThreadClass1._waitTillParametersChange.Set(); //Notifying the thread that the parameters might have chnaged
}
}
}
The above implementation is working fine for me. I have to start the FileWatcher from the Main() using the following lines:
public static void Main()
{
ReadXml.ReadXmlParameters();
ReadXml.CreateXMLWatcher();
// Start other threads now
}
and then I start my other threads.
QUESTION: Since with the above-mentioned implementation, I have got Static methods and variables in my program so, I am wondering if this is the proper (at least acceptable) implementation of a FileWatcher or should I try to get rid of these static things by implementing ReadXml as a singleton class (or providing the same object to all the thread classes).

Filesystemwatcher doesn't trigger event

I am trying to monitor a directory for new files in it with the FileSystemWatcher Class.
My Problem is that the event doesn't get triggered. My watcher class is:
public class Filewatcher
{
private FileSystemWatcher watcher;
public Filewatcher(string path, string filefilter)
{
this.watcher = new FileSystemWatcher();
this.watcher.Path = path;
this.watcher.NotifyFilter = NotifyFilters.FileName; //| NotifyFilters.LastWrite | NotifyFilters.LastAccess
this.watcher.Filter = filefilter;
this.watcher.Created += new FileSystemEventHandler(OnChanged);
}
public void start_watching()
{
//this.watcher.IncludeSubdirectories = true;
this.watcher.EnableRaisingEvents = true;
Console.WriteLine("Press Enter to quit\r\n");
Console.ReadLine();
}
private static void OnChanged(object source, FileSystemEventArgs e)
{
//FileInfo objFileInfo = new FileInfo(e.FullPath);
//if (!objFileInfo.Exists) return;
Console.WriteLine("got the change\r\n");
global_functions.perform_action(Global_Vars.thereader.read(e.FullPath), Global_Vars.thepattern);
}
}
Operating System is Win 7 Prof x64
You don't make a call to start_watching(). Add a call to that and it may work better.

Categories

Resources