Bob T.
Bob T.

Reputation: 261

C# : FileSystemWatcher - multiple watching folders issue

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

Answers (3)

ionutioio
ionutioio

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

Dirk
Dirk

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

Hinek
Hinek

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

Related Questions