1

Possible Duplicate:
Detecting moved files using FileSystemWatcher

I'm trying to monitor moved files with the FileSystemWatcher, and got some help on the way here:

Using FileSystemWatcher with multiple files

However, I found I had to be able to use both the Deleted and the Created events in order to get the paths from where the files have been moved as well as the path to where they have been moved. But when I add similar code for the Delete event, I can only get either one or the other event to trigger. And it seems to be the order of where I wire the events that determines which event will run. So if I put the Created event last in the wiring code, that will run, and vice versa, if I put the Delete wiring last, that will run, but not Created.

Here's the code:

public class FileListEventArgs : EventArgs
{
    public List<string> FileList { get; set; }
}

public class Monitor
{
    private List<string> filePaths;
    private List<string> deletedFilePaths;
    private ReaderWriterLockSlim rwlock;
    private Timer processTimer;
    private Timer deletionTimer;
    public event EventHandler FileListCreated;
    public event EventHandler FileListDeleted;


    public void OnFileListCreated(FileListEventArgs e)
    {
        if (FileListCreated != null)
            FileListCreated(this, e);
    }

    public void OnFileListDeleted(FileListEventArgs e)
    {
        if (FileListDeleted != null)
            FileListDeleted(this, e);
    }

    public Monitor(string path)
    {
        filePaths = new List<string>();
        deletedFilePaths = new List<string>();

        rwlock = new ReaderWriterLockSlim();

        FileSystemWatcher watcher = new FileSystemWatcher();
        watcher.Filter = "*.*";
        watcher.Deleted += new FileSystemEventHandler(watcher_Deleted);
        watcher.Created += watcher_FileCreated;


        watcher.Path = path;
        watcher.IncludeSubdirectories = true;
        watcher.EnableRaisingEvents = true;
    }


    private void ProcessQueue()
    {
        try
        {
            Console.WriteLine("Processing queue, " + filePaths.Count + " files created:");
            rwlock.EnterReadLock();

        }
        finally
        {
            if (processTimer != null)
            {
                processTimer.Stop();
                processTimer.Dispose();
                processTimer = null;
                OnFileListCreated(new FileListEventArgs { FileList = filePaths });
                filePaths.Clear();
            }
            rwlock.ExitReadLock();
        }
    }

    private void ProcessDeletionQueue()
    {
        try
        {
            Console.WriteLine("Processing queue, " + deletedFilePaths.Count + " files created:");
            rwlock.EnterReadLock();

        }
        finally
        {
            if (processTimer != null)
            {
                processTimer.Stop();
                processTimer.Dispose();
                processTimer = null;
                OnFileListDeleted(new FileListEventArgs { FileList = deletedFilePaths });

                deletedFilePaths.Clear();
            }
            rwlock.ExitReadLock();
        }
    }

    void watcher_FileCreated(object sender, FileSystemEventArgs e)
    {
        try
        {
            rwlock.EnterWriteLock();
            filePaths.Add(e.FullPath);

            if (processTimer == null)
            {
                // First file, start timer.
                processTimer = new Timer(2000);
                processTimer.Elapsed += (o, ee) => ProcessQueue();
                processTimer.Start();
            }
            else
            {
                // Subsequent file, reset timer. 
                processTimer.Stop();
                processTimer.Start();
            }

        }
        finally
        {
            rwlock.ExitWriteLock();
        }
    }

    void watcher_Deleted(object sender, FileSystemEventArgs e)
    {
        try
        {
            rwlock.EnterWriteLock();
            deletedFilePaths.Add(e.FullPath);

            if (deletionTimer == null)
            {
                // First file, start timer.
                deletionTimer = new Timer(2000);
                deletionTimer.Elapsed += (o, ee) => ProcessDeletionQueue();
                deletionTimer.Start();
            }
            else
            {
                // Subsequent file, reset timer. 
                deletionTimer.Stop();
                deletionTimer.Start();
            }

        }
        finally
        {
            rwlock.ExitWriteLock();
        }
    }

So how do I do this to get the original path where the files were, as well as the new path to where they have been moved? (See the first question for why the timer code is there in order to hold off the handling of the events until all files have been moved in a multifile move).

Community
  • 1
  • 1
Anders
  • 12,556
  • 24
  • 104
  • 151
  • I don't think so. I have no problem with using the file name to compare the files, as in that post. The problem is I can't get both delete and create events to trigger. Or at least all I see is that the create event is triggered and the delete has not done so yet. In my main class I need to take the created files list and compare it to the deleted files list, but the deleted files list is empty, while the created files list is filled. – Anders Aug 05 '11 at 09:22

2 Answers2

1

You declare two timers, but you only use one of them (you use the same one in the process deletion queue method). So looks like a simple copy/paste mistake to begin with.

Anders Forsgren
  • 10,827
  • 4
  • 40
  • 77
  • Thanks, that was an attempt from me to get it to work, but I missed changing some stuff with the copy and paste as you said. It didn't help fixing that mistake though, but it got me looking it over again, and I found that if I triggered both events in the same ProcessQueue method it did work, so I'll credit you for that. – Anders Aug 05 '11 at 13:48
0

I have found that FileSystemWatcher events are NOT queued (caveat: this was about 8 years ago).

If you are processing a file, and 3 new files get created while processing, you will not get the 3 events.

After processing a file, you may need to manually check the directory for other changes.

Steve Wellens
  • 20,506
  • 2
  • 28
  • 69
  • Well, I do get 3 events for moving 3 files... But the problem is I can't get both the delete and the create event to trigger, only one or the other. – Anders Aug 05 '11 at 09:20
  • Are you just monitoring ONE directory? If you move a file, it can't stay in the same directory. If a file is moved out, you'll get the deleted event. If a file is moved in, you get the created event. I don't see how you could get both. – Steve Wellens Aug 05 '11 at 12:34