【问题标题】:FileSystemWatcher used to watch for folder/file openFileSystemWatcher 用于监视文件夹/文件打开
【发布时间】:2013-02-08 19:06:38
【问题描述】:

我已经浏览过,但找不到任何关于我正在寻找的信息,如果有其他帖子已经涵盖了这个,那么我很抱歉。

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

文件夹名称是 C:\Junk

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

【问题讨论】:

  • 如果文件夹名称是 C:\JUNK,为什么不把它放在 Path 属性中呢? Filter 属性用于筛选文件而不是文件夹
  • @Steve - 根据您的建议,我更改了代码,但在打开文件夹时仍未触发。
  • 尝试使用文件系统过滤驱动来跟踪这种变化。其他变体效果不佳。
  • 为了快速完成这项工作,我只是依靠 NTFS 安全审计层。

标签: c# .net wpf filesystemwatcher


【解决方案1】:

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

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

您应该查看ReadDirectoryChangesW Win32 函数,记录在here。它可以传递一个FILE_NOTIFY_CHANGE_LAST_ACCESS 标志,这似乎可以提供您想要的:

对监视目录或子树中文件的最后访问时间的任何更改都会导致更改通知等待操作返回。

编辑:忽略这一点,FileSystemWatcher 确实在内部将 NotifyFilters.LastWrite 作为 int 32 传递给 FILE_NOTIFY_CHANGE_LAST_ACCESS,这与 FILE_NOTIFY_CHANGE_LAST_ACCESS 相同。然后那个函数仍然没有通知文件访问,我试过了。

也许这是由this引起的:

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

fsutil behavior set disablelastaccess 0

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

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

如果禁用该行为后仍然无法正常工作,请等待 Raymond Chen(或他自己)的建议箱出现,通常有一个非常合乎逻辑的解释来解释为什么文档似乎没有正确描述您遇到的行为. ;-)

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

【讨论】:

  • 首先尝试实现它... ;)
  • 这似乎是一个 PITA 但那是另一次了,现在我很高兴我有一条路要走。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    你应该设置

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

    如果事件应该针对所有文件触发,则删除 watcher.Filter

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

    【讨论】:

    • 我已按照建议更改了我的代码,但仍然没有打开触发器。
    【解决方案4】:

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

    【讨论】:

      【解决方案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 已经给出了答案,在我看来这是唯一好的答案,即使有点太短了。

        我只想添加几句话和一个链接,感兴趣的用户可以开始。

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

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

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

        要在启动可执行文件之前捕获它的启动时间(以及大量其他“事件”),并在可执行文件的代码加载到内存之前执行一些操作,您需要在较低(内核)级别编写一些东西,也就是说,您需要构建一个驱动程序,在这种特定情况下是一个(微过滤器)文件系统驱动程序。

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-08-31
          • 2013-01-18
          • 1970-01-01
          • 2023-03-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-12-19
          相关资源
          最近更新 更多