FileSystemWatcher used to watch for folder/file open

Jesse picture Jesse · Feb 8, 2013 · Viewed 13.9k times · Source

I have browsed around but cannot find any information on what I am seeking, if there is another post that already goes over this then I apologize.

I am seeking help with code that will monitor a specific folder for when the folder is opened by another person or when a file under said folder is opened. At this point I can see when a user opens and modifies any files but if they just open the file to view it, it does not throw an event even when I add LastAccessed. Any information or help would be appreciated.

Folder name is C:\Junk

Code in C# 4.0:

    [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
    public static void Run()
    {


        FileSystemWatcher watcher = new FileSystemWatcher();
        watcher.Path = @"C:\";
        watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
           | NotifyFilters.FileName | NotifyFilters.DirectoryName;
        watcher.Filter = "junk";

        // Add event handlers.
        watcher.Changed += new FileSystemEventHandler(OnChanged);
        watcher.Created += new FileSystemEventHandler(OnChanged);
        watcher.Deleted += new FileSystemEventHandler(OnChanged);
        watcher.Renamed += new RenamedEventHandler(OnRenamed);
        watcher.IncludeSubdirectories = true;
        watcher.EnableRaisingEvents = true;

        // Wait for the user to quit the program.
        Console.WriteLine("Press \'q\' to quit the sample.");
        while (Console.Read() != 'q') ;
    }

    // Define the event handlers. 
    private static void OnChanged(object source, FileSystemEventArgs e)
    {
        // Specify what is done when a file is changed, created, or deleted.
        Console.WriteLine("File: " + e.FullPath + " " + e.ChangeType);
    }

    private static void OnRenamed(object source, RenamedEventArgs e)
    {
        // Specify what is done when a file is renamed.
        Console.WriteLine("File: {0} renamed to {1}", e.OldFullPath, e.FullPath);
    }

Answer

CodeCaster picture CodeCaster · Feb 8, 2013

it does not throw an event even when I add LastAccessed.

Because NotifyFilters.LastAccessed specifies that you wish to retreive that property, not the event to subscribe to. The available events are Changed, Created, or Deleted, none of which does what you want.

You should take a look at the ReadDirectoryChangesW Win32 function, documented here. It can be passed a FILE_NOTIFY_CHANGE_LAST_ACCESS flag, which seems to deliver what you want:

Any change to the last access time of files in the watched directory or subtree causes a change notification wait operation to return.

Edit: disregard this, the FileSystemWatcher does internally pass NotifyFilters.LastWrite as int 32, which is the same as FILE_NOTIFY_CHANGE_LAST_ACCESS, to ReadDirectoryChangesW. That function then still does not notify on file access, I've tried.

Perhaps this is caused by this:

Last Access Time has a loose granularity that only guarantees that the time is accurate to within one hour. In Windows Vista, we've disabled updates to Last Access Time to improve NTFS performance. If you are using an application that relies on this value, you can enable it using the following command:

fsutil behavior set disablelastaccess 0

You must restart the computer for this change to take effect.

If you execute that on the command prompt, perhaps then the LastAccess will be written and the event will fire. I'm not going to try in on my SSD and don't have a VM ready, but on Windows 7 disablelastaccess seems to be enabled out-of-the-box.

If it still doesn't work when you disable that behavior, wait for Raymond Chen's suggestion box (or himself) to come by, usually there's a quite logical explanation for why the documentation does not seem to correctly describe the behaviour you encounter. ;-)

You may as well just scan the directory in a loop and look at the LastAccessed property of the Files. What are you trying to do when a user opens a certain file?