Reputation: 261
Im trying write program in c# which is watching multiple folders. If in any of watched folders are added file, program should create copy in defined paths. My problem is when i create file, program create copies in wrong folder
e.g. if i add file into
C:\folder1\stuff\it should create copy in
D:\stuff1\copied1...3\but instead it created copies in
D:\stuff2\copied1...3\
There is code :
namespace Watcher { public class Watcher { struct Paths { public string sourcePath; public List<string> destinations; public FileSystemWatcher Watcher; } List<Paths> paths = new List<Paths>(); public Watcher() { createWatchTower(); } public void watch() { foreach (Paths p in paths) { p.Watcher.Created += (sender, e) => onCreate(sender, e, p.destinations); } } void createWatchTower() { Paths p1; p1.destinations = new List<string>(); p1.sourcePath = @"C:\folder1\stuff\"; p1.Watcher = new FileSystemWatcher(); p1.Watcher.Path = p1.sourcePath; p1.Watcher.EnableRaisingEvents = true; p1.destinations.Add(@"D:\stuff1\copied1\"); p1.destinations.Add(@"D:\stuff1\copied2\"); p1.destinations.Add(@"D:\stuff1\copied3\"); paths.Add(p1); Paths p2; p2.destinations = new List<string>(); p2.sourcePath = @"C:\folder2\stuff2"; p2.Watcher = new FileSystemWatcher(); p2.Watcher.Path = p2.sourcePath; p2.Watcher.EnableRaisingEvents = true; p2.destinations.Add(@"D:\stuff2\copied1\"); p2.destinations.Add(@"D:\stuff2\copied2\"); p2.destinations.Add(@"D:\stuff2\copied3\"); paths.Add(p2); } private void onCreate(object o, FileSystemEventArgs e, List<string> dest) { foreach (string s in dest) { try { System.IO.File.Copy(e.FullPath, s + e.Name, true); } catch (Exception ex) { Console.WriteLine(ex); } } } } }
Could anyone help me ? I think its because event in foreach, but i cant find sollution for this. Thanks much post
Upvotes: 0
Views: 1997
Reputation: 238
I had a similar program running as a windows service. I created an XML configuration file with all the folders to watch, and the destination path corresponding to each path. Then, I had another watcher thread for each folder to watch.
In order to have the right output path, you need to pair it with the folder you are watching. Thus, you can use either a config file, or something like a Dictionary or a List of KeyValuePairs.
Upvotes: 0
Reputation: 10958
If you are not using C# 5 then the problem is the closure on p
in the foreach-loop in the watch
method:
foreach (Paths p in paths)
{
p.Watcher.Created += (sender, e) => onCreate(sender, e, p.destinations);
}
When using p
inside the lambda it will capture the variable, not its value. So if the Created
event is raised p
will refer to the last item of the paths
list.
You can avoid that by introducing a temporary variable inside the foreach-loop:
foreach (Paths p in paths)
{
var tmp = p;
p.Watcher.Created += (sender, e) => onCreate(sender, e, tmp.destinations);
}
You can find a more detailed analysis of what changed in C# 5 in this Stackoverflow question.
Upvotes: 5
Reputation: 9729
You could create paths as a Dictionary
(sourcePath => p) instead of a List
and in the onCreate
method get the destionations by calling
var dest = paths[((FileSystemWatcher)sender).Path].destinations
Upvotes: 0