Search code examples
c#filesystemwatcher

FileSystem watcher onChanged after file Copy


This code is from another stack answer, essentially i'm trying to watch the Users folder in for new files, I understand that OnCreate would fire before the new document has been completely "copied/downloaded", What i'm trying to do is copy it at each onChange event, however the copying doesn't seem to trigger the onChange once its complete despite the Microsoft docs saying it does?

For the record onCreate works fine. waitingForClose is declared as a public string list, onCreate adds the the file fine.

   private void MetroWindow_Loaded(object sender, RoutedEventArgs e)
    {
        FileSystemWatcher watcher = new FileSystemWatcher();
        watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.Size;
        watcher.Path = @"C:\Users\MyUser";
        watcher.IncludeSubdirectories = true;
        watcher.Created += new FileSystemEventHandler(onCreate);
        watcher.Changed += new FileSystemEventHandler(onChanged);
        watcher.EnableRaisingEvents = true;
    }

onCreate - This fires:

  void onCreate(object sender, FileSystemEventArgs e)
    {
        var fileName = e.Name;
        var destPath = @"C:\Users\myUser\Desktop\someFolder";
        var destfile = System.IO.Path.Combine(destPath, fileName);
        if (fileName.Substring(fileName.Length - 3, 3) == "doc" || fileName.Substring(fileName.Length - 3, 3) == "pdf" || fileName.Substring(fileName.Length - 4, 4) == "docx")
        {
            try
            {
                System.IO.File.Copy(e.FullPath, destfile, true);
            }
            catch
            {
                waitingForClose.Add(e.FullPath);
            }
          Console.WriteLine("File:" + e.FullPath + " " + e.ChangeType);

        }
    }

onChanged- this NEVER fires for the file at all, even during the copy:

void onChanged(object sender, FileSystemEventArgs e)
{
    var fileName = e.Name;
    var destPath = @"C:\Users\myUser\Desktop\someFolder";
    var destfile = System.IO.Path.Combine(destPath, fileName);

    if (fileName.Substring(fileName.Length - 3, 3) == "doc" || fileName.Substring(fileName.Length - 3, 3) == "pdf" || fileName.Substring(fileName.Length - 4, 4) == "docx")
    {


        if (waitingForClose.Contains(e.FullPath))
        {
            try
            {
                System.IO.File.Copy(e.FullPath, destfile, true);
                waitingForClose.Remove(e.FullPath);
            }
            catch { }
        }
    }

}

Ok from the looks of it this is a windows 8 issue will post a solution shortly!


Solution

  • Ok,

    From the looks of it the FilesystemWatcher onChanged event is iffy(broken at the moment) at best for Windows 8.1.

    What i've ended up doing is creating an array of files from onCreate and then trying to copy from that array every 5 seconds: Like so:

       void onCreate(object sender, FileSystemEventArgs e)
        {
            var fileName = e.Name;
            var destPath = @"C:\Users\myuser\Desktop\Repo";
            var destfile = System.IO.Path.Combine(destPath, fileName);
            if (fileName.Substring(fileName.Length - 3, 3) == "doc" || fileName.Substring(fileName.Length - 3, 3) == "pdf" || fileName.Substring(fileName.Length - 4, 4) == "docx")
            {
    // We don't want to track the file if it's triggered a created event because it's copied to our repo.
                if (!fileName.Contains("Repo"))
                {
                    try
                    {
                        System.IO.File.Copy(e.FullPath, destfile, true);
                    }
                    catch
                    {
                       waitingForClose.Add(e.FullPath);
                    }
                    Console.WriteLine("File:" + e.FullPath + " " + e.ChangeType);
    
                } // if (!fileName.Contains("repo"))
            } //  if (fileName.Substring(fileName.Length
        } // void onCreate(
    

    So now we have an array of files we're waiting to actually finish creating I'm doing this in the Window_onLoad event:

       System.Windows.Threading.DispatcherTimer dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
        dispatcherTimer.Tick += new EventHandler(onTick);
        dispatcherTimer.Interval = new TimeSpan(0, 0, 5);
        dispatcherTimer.Start();
    

    Now on the OnTick Event

      void onTick(object sender, EventArgs e)
        {
            List<String> tempList = new System.Collections.Generic.List<String>();
    
            foreach(String item in waitingForClose){
    
                  try
                  {
                        System.IO.File.Copy(System.IO.Path.GetFullPath(item), @"C:\Users\myuser\Desktop\Repo\" + System.IO.Path.GetFileName(item), true);
                        tempList.Add(item);
                    }
                    catch  {
                        // Do nothing
                    }
                }
            waitingForClose.RemoveAll(i => tempList.Contains(i));
        }