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

我浏览过但却无法找到有关我所寻求内容的任何信息,如果还有其他post已经过去,那么我道歉。

我正在寻求帮助代码,该代码将监视特定文件夹,以便在其他人打开文件夹时或打开所述文件夹下的文件时。 此时我可以看到用户打开并修改任何文件的时间,但如果他们只是打开文件来查看它,即使我添加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); } 

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

因为NotifyFilters.LastAccessed指定您希望检索该属性,而不是要订阅的事件。 可用事件是“ Changed ,“ Changed Created ”或“ Deleted ,但这些事件都不是您想要的。

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

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

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

也许这是由此引起的:

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

 fsutil behavior set disablelastaccess 0 

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

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

如果在禁用该行为时它仍然无效,请等待Raymond Chen的建议框(或他自己)过来,通常有一个非常合乎逻辑的解释,说明为什么文档似乎没有正确描述您遇到的行为。 😉

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

你应该设置

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

如果要为所有文件触发事件,请删除watcher.Filter

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

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

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

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