129

I am using a Windows Forms Application to monitor a directory and move the files dropped in it to another directory.

At the moment it will copy the file to another directory, but when another file is added it will just end with no error message. Sometimes it does copy two files before ending on the third.

Is this because I am using a Windows Form Application rather than a console app? Is there a way I can stop the program from ending and to keep watching the directory?

private void watch()
{
  this.watcher = new FileSystemWatcher();
  watcher.Path = path;
  watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
                         | NotifyFilters.FileName | NotifyFilters.DirectoryName;
  watcher.Filter = "*.*";
  watcher.Changed += OnChanged;
  watcher.EnableRaisingEvents = true;
}

private void OnChanged(object source, FileSystemEventArgs e)
{
  //Copies file to another directory.
}

public void Dispose()
{
  // avoiding resource leak
  watcher.Changed -= OnChanged;
  this.watcher.Dispose();
}
astrowalker
  • 3,123
  • 3
  • 21
  • 40
deepseapanda
  • 3,717
  • 8
  • 32
  • 39

3 Answers3

169

The problem was the notify filters. The program was trying to open a file that was still copying. I removed all of the notify filters except for LastWrite.

private void watch()
{
  FileSystemWatcher watcher = new FileSystemWatcher();
  watcher.Path = path;
  watcher.NotifyFilter = NotifyFilters.LastWrite;
  watcher.Filter = "*.*";
  watcher.Changed += new FileSystemEventHandler(OnChanged);
  watcher.EnableRaisingEvents = true;
}
Victor Zakharov
  • 25,801
  • 18
  • 85
  • 151
deepseapanda
  • 3,717
  • 8
  • 32
  • 39
  • 8
    Hi, I was using this approach but when I copy a file the event is raised twice: one time when file is created empty (copy starts) and one more time when copy finishes. How to avoid this duplicated event, any filter able to handle it without a custom control of that? – dhalfageme Jan 30 '19 at 11:08
  • @dhalfageme I check on both events if anything meaningful for my application appears in the folder. – Eftekhari Feb 22 '20 at 11:55
37

You did not supply the file handling code, but I assume you made the same mistake everyone does when first writing such a thing: the filewatcher event will be raised as soon as the file is created. However, it will take some time for the file to be finished. Take a file size of 1 GB for example. The file may be created by another program (Explorer.exe copying it from somewhere) but it will take minutes to finish that process. The event is raised at creation time and you need to wait for the file to be ready to be copied.

You can wait for a file to be ready by using this function in a loop.

Community
  • 1
  • 1
nvoigt
  • 75,013
  • 26
  • 93
  • 142
29

The reason may be that watcher is declared as local variable to a method and it is garbage collected when the method finishes. You should declare it as a class member. Try the following:

FileSystemWatcher watcher;

private void watch()
{
  watcher = new FileSystemWatcher();
  watcher.Path = path;
  watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
                         | NotifyFilters.FileName | NotifyFilters.DirectoryName;
  watcher.Filter = "*.*";
  watcher.Changed += new FileSystemEventHandler(OnChanged);
  watcher.EnableRaisingEvents = true;
}

private void OnChanged(object source, FileSystemEventArgs e)
{
  //Copies file to another directory.
}
Aage
  • 5,932
  • 2
  • 32
  • 57
user1912419
  • 496
  • 3
  • 4
  • 21
    `watcher` variable is kept alive (not garbage collected) because he subscribed to Changed event. – adospace Aug 04 '16 at 12:33
  • 1
    I believe it is actually because EnableRaisingEvents is set to `true`. I do not think the status of member event handlers have to do with garbage collection. I think EnableRaisingEvents has, what I might favorably call, a special behavior in this case. – Matias Grioni Feb 27 '19 at 00:55