2013-02-08 32 views
6

我浏览过但找不到任何有关我正在寻找的信息,如果有另一篇文章已经过去,那么我表示歉意。FileSystemWatcher用于监视文件夹/文件打开

我在寻找关于监视特定文件夹的代码的帮助,该特定文件夹用于何时该文件夹被另一个人打开或当该文件夹下的文件被打开时。此时,我可以看到用户何时打开和修改任何文件,但是如果他们只是打开文件来查看它,即使添加LastAccessed也不会抛出事件。任何信息或帮助将不胜感激。

文件夹名称是C:\垃圾

代码在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); 
    } 
+0

如果文件夹名称是C:\ JUNK,为什么不把它放在Path属性中? Filter属性用于屏幕文件不是文件夹 – Steve 2013-02-08 19:12:48

+0

@Steve - 根据你的建议,我改变了我的代码,但它仍然没有触发打开文件夹。 – Saren 2013-02-08 19:15:39

+1

尝试使用文件系统筛选器驱动程序来跟踪这种更改。其他变体不能很​​好地工作。 – 2013-02-09 08:07:01

回答

0

您应该设置

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

和删除watcher.Filter行,如果事件应该解雇所有文件

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

+0

我已经改变了我的代码建议,但仍然没有触发开放。 – Saren 2013-02-08 19:16:02

2

即使添加LastAccessed,它也不会抛出事件。

因为NotifyFilters.LastAccessed指定您希望检索该属性,而不是要订阅的事件。可用的事件是ChangedCreatedDeleted,其中没有一个是您想要的。

你应该看看ReadDirectoryChangesW Win32函数,记录在here。它可以通过一个FILE_NOTIFY_CHANGE_LAST_ACCESS标志,这似乎提供你想要的东西:

任何变化在看着目录或树文件的最后访问时间引起变化通知给等待操作返回。

编辑:忽略这一点,并FileSystemWatcher内部传递NotifyFilters.LastWrite为INT 32,其是相同的FILE_NOTIFY_CHANGE_LAST_ACCESS,到ReadDirectoryChangesW。该功能,然后仍然不通知文件访问,我试过了。

也许这是由this造成的:

上次访问时间有一个宽松的粒度,只有保证了时间精确到一个小时之内。在Windows Vista中,我们已禁用了上次访问时间的更新以提高NTFS性能。如果您使用的是依赖于该值的应用程序,你可以使用下面的命令启用它:

fsutil behavior set disablelastaccess 0 

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

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

如果在禁用该行为时仍不起作用,请等待Raymond Chen的建议框(或自己)过来,通常有一个非常合理的解释,为什么文档似乎没有正确描述您的行为遭遇。 ;-)

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

+0

非常感谢! – Saren 2013-02-08 19:27:11

+0

首先尝试实施它;;) – CodeCaster 2013-02-08 19:27:39

+0

它似乎是一个PITA,但这是另一次,现在我很高兴我有一个路线。 – Saren 2013-02-08 19:28:30

0

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

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

要获得On-Access文件路径,有一个小型过滤器驱动程序的解决方案。您必须实施小型过滤器驱动程序才能实施要求。