FileSystemWatcher used to watch for folder/file open

旧街凉风 提交于 2019-12-28 02:11:08

问题


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);
    }

回答1:


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?




回答2:


To get On-Access file path there is one solution of minifilter driver. You have to implement minifilter driver to get the requirements implemented.




回答3:


You should set

watcher.Path = @"C:\junk";

and delete watcher.Filter line if event should fire for all files

Using Filter property you can set wildcards for matching files, for example *.txt




回答4:


what you really need is NtQuerySystemInformation enumeration and a timer, that way you can scan the directory and see if any of the files are open. the filesystemwatcher will not give you this info




回答5:


public void OnChanged(object sender, FileSystemEventArgs e)
{
    string FileName = System.IO.Path.GetFileName(e.FullPath);

    if(IsAvailable(System.IO.Path.Combine(RecievedPath,FileName)))
    {
        ProcessMessage(FileName);
    }
}


private void ProcessMessage(string fileName)
{
    try
    {
       File.Copy(System.IO.Path.Combine(RecievedPath,fileName), System.IO.Path.Combine(SentPath,fileName));
        MessageBox.Show("File Copied");
    }
    catch (Exception)
    { }
}

private static bool IsAvailable(String filePath)
{
    try
    {
        using (FileStream inputStream = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.None))
        {
            if (inputStream.Length > 0)
            {
                return true;
            }
            else
            {
                return false;
            }

        }
    }
    catch (Exception)
    {
        return false;
    }
}



回答6:


Digvijay Rathore gave already an answer, in my opinion the only good answer, even if a bit too short.

I want just to add a few words and a link where interested users could start.

The FileSystemWatcher is useful just to monitor what is happening inside the monitored folder, but it's not able to monitor and intercept what the user (or the OS) is doing.

For example, with a FSW (FileSystemWatcher) you can monitor when a file/folder is created, deleted, renamed or changed in some way, and those events are unleashed AFTER the action is completed, not before nor while.

A simple FSW is not able to know if the user is launching an executable from the monitored folder, in this case it will simply generate no events at all.

To catch when an executable is launched (and tons of other "events") before it is launched and make some action before the code of the executable is loaded in memory, you need to write something at lower (kernel) level, that is, you need to build a driver, in this specific case a (minifilter) File System driver.

This is a good starting point to start to understand the basic of Minifilter Windows Drivers:

https://docs.microsoft.com/en-us/windows-hardware/drivers/ifs/file-system-minifilter-drivers



来源:https://stackoverflow.com/questions/14779616/filesystemwatcher-used-to-watch-for-folder-file-open

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!