wpf FileSystemWatcher 用于监视文件夹/文件打开

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14779616/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 07:25:58  来源:igfitidea点击:

FileSystemWatcher used to watch for folder/file open

c#.netwpffilesystemwatcher

提问by Jesse

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.

我正在寻求有关代码的帮助,该代码将监视特定文件夹何时被其他人打开或何时打开所述文件夹下的文件。在这一点上,我可以看到用户何时打开和修改任何文件,但如果他们只是打开文件来查看它,即使我添加 LastAccessed,它也不会引发事件。任何信息或帮助将不胜感激。

Folder name is C:\Junk

文件夹名称是 C:\Junk

Code in C# 4.0:

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

回答by CodeCaster

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

即使我添加 LastAccessed,它也不会引发事件。

Because NotifyFilters.LastAccessedspecifies 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.

因为NotifyFilters.LastAccessed指定您希望检索该属性,而不是要订阅的事件。可用的事件是ChangedCreatedDeleted,它们都不能满足您的需求。

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

您应该查看此处ReadDirectoryChangesW记录的Win32 函数。它可以传递一个标志,它似乎提供了你想要的东西:FILE_NOTIFY_CHANGE_LAST_ACCESS

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 FileSystemWatcherdoes internally pass NotifyFilters.LastWriteas 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.

编辑:无视这一点,FileSystemWatcher确实在内部传递NotifyFilters.LastWrite为 int 32,这与FILE_NOTIFY_CHANGE_LAST_ACCESS, to相同ReadDirectoryChangesW。然后该功能仍然不通知文件访问,我试过了。

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.

上次访问时间具有松散的粒度,仅保证时间精确到一小时以内。在 Windows Vista 中,我们已禁用对上次访问时间的更新以提高 NTFS 性能。如果您正在使用依赖此值的应用程序,则可以使用以下命令启用它:

fsutil behavior set disablelastaccess 0

您必须重新启动计算机才能使此更改生效。

If you execute that on the command prompt, perhaps then the LastAccesswill 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 disablelastaccessseems to be enabled out-of-the-box.

如果您在命令提示符下执行该操作,则可能LastAccess会写入该事件并触发该事件。我不会尝试使用我的 SSD 并且没有准备好 VM,但在 Windows 7 上disablelastaccess似乎是开箱即用的。

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

如果禁用该行为后仍然不起作用,请等待 Raymond Chen 的意见箱(或他自己)出现,通常对于文档似乎没有正确描述您遇到的行为的原因有一个非常合乎逻辑的解释。;-)

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 whena user opens a certain file?

您也可以循环扫描目录并查看文件的 LastAccessed 属性。用户打开某个文件时,您想做什么

回答by Digvijay Rathore

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

要获取 On-Access 文件路径,有一种 minifilter 驱动程序的解决方案。您必须实现微过滤器驱动程序才能实现要求。

回答by radiolondra

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

Digvijay Rathore 已经给出了答案,在我看来这是唯一好的答案,即使有点太短了。

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.

FileSystemWatcher 仅用于监视受监视文件夹内发生的事情,但它无法监视和拦截用户(或操作系统)正在执行的操作。

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.

例如,使用 FSW (FileSystemWatcher),您可以监控文件/文件夹何时以某种方式被创建、删除、重命名或更改,并且这些事件在操作完成后释放,而不是之前或之后。

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.

一个简单的 FSW 无法知道用户是否正在从受监控的文件夹启动可执行文件,在这种情况下,它根本不会生成任何事件。

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:

这是开始了解 Minifilter Windows 驱动程序基础的一个很好的起点:

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

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

回答by Alex

what you really need is NtQuerySystemInformationenumeration 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

您真正需要的是NtQuerySystemInformation枚举和计时器,这样您就可以扫描目录并查看是否有任何文件打开。文件系统观察者不会给你这个信息

回答by Ajay Kumar

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

回答by VladL

You should set

你应该设置

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

and delete watcher.Filterline if event should fire for all files

并删除watcher.Filter行,如果事件应该为所有文件触发

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

使用Filter属性,您可以为匹配的文件设置通配符,例如*.txt