2012-03-05 42 views
4

我想,当一个文件在磁盘上的更新,以得到一个通知。我有兴趣在发生刷新时立即获取此通知,但似乎FileSystemWatcher只会在流打开或关闭时发送事件。FileSystemWatcher的改变事件(“LastWrite”)是不可靠的

在下面我写一个文件,并多次刷新缓冲区到磁盘的代码。然而,FileSystemWatcher在写入开始时只通知过一次,当它们结束时一次。

是否有另一种方式来获得这些通知?或者我应该使用投票吗?

的代码:

class Program 
{ 
    static void Main(string[] args) 
    { 
     FileSystemWatcher watcher = new FileSystemWatcher(Environment.CurrentDirectory, "Test.txt"); 
     watcher.Changed += watcher_Changed; 
     watcher.EnableRaisingEvents = true; 

     using(TextWriter writer = new StreamWriter("Test.txt")) 
     { 
      WriteData(writer); 
      WriteData(writer); 
      WriteData(writer); 
      WriteData(writer); 
     } 

     Thread.Sleep(10000); 
    } 

    private static void WriteData(TextWriter writer) 
    { 
     writer.WriteLine("Hello!"); 
     writer.Flush(); 
     Console.WriteLine(DateTime.Now.ToString("T") + "] Wrote data"); 
     Thread.Sleep(3000); 
    } 

    static void watcher_Changed(object sender, FileSystemEventArgs e) 
    { 
     Console.WriteLine(DateTime.Now.ToString("T") + "] Watcher changed!"); 
    } 
} 

UPDATE 1

我已经纠正了日期时间的ToString函数来显示秒。这里是与上面的代码输出:

11:37:47 AM] Watcher changed! 
11:37:47 AM] Wrote data 
11:37:50 AM] Wrote data 
11:37:53 AM] Wrote data 
11:37:56 AM] Wrote data 
11:37:59 AM] Watcher changed! 

谢谢!

+2

'FileSystemWatcher'是靠不住的出于很多原因。如果您需要所有更新的可靠通知,请更改双方并在它们之间使用其他显式通信通道。 – 2012-03-05 08:51:24

+0

我同意,这将是一个更好的选择,但在我的情况下是不可能的。 – VitalyB 2012-03-05 09:40:42

+0

啊,我从你的示例代码/描述中假设你是在控制这个集成问题两边的代码。如果情况并非如此,不知道我会推荐什么。我会想一想。 – 2012-03-05 10:12:41

回答

1

它与FileSystemWatcher无关。观察者对文件系统的LastWrite属性进行更新。

E.g. NTFS不会在每次写入时更新LastWrite。该值被缓存,并且只在流关闭时或在其他未指定的时间写入。 This document

时间戳更新在不同的时间和各种原因。关于文件时间戳的唯一保证是当更改的句柄关闭时文件时间正确地反映出来。 [...] NTFS文件系统延迟更新最后访问时间达1小时的文件的上次访问后

我假设一个类似的缓存适用于写

+0

有趣!这是事实,这可能是原因。 – VitalyB 2012-03-05 12:30:22

2

我认为你的一个问题在于,你的所有写入在事件获得一片cpu-time之前得到执行。 MSDN states

Changed事件被更改时,系统属性,上次写入时间,在目录中的文件或目录的上次访问时间或安全权限被监视的大小就提高。

我做了一个测试,每次调用写数据(...),我得到了什么之后插入卧具是

09:32]看守变了!

09:32]看守变了!

9点32] - - - - >写数据

9点32] - - - - >写数据

9点32] - - - - >写数据

09:32] ----->写数据

09:32]看守者改变!

09:32]看守变了!

我猜这种证明在你调用Flush()之后就会触发even,这只是一个事件处理程序何时执行的问题(并且我认为它也将事件分组)。 我不知道你的项目的具体需求,但我不会投票。看起来很浪费,因为FileSystemWatcher在我看来是做你想做的。

编辑:好的,我想我的大脑还没有准备好,但是当我发布这个时候还没有准备好思考。 你的结论是,当你打开和关闭流时,它会触发,这似乎更合乎逻辑和正确。 我想我正在寻找“证明”,当你调用flush并因此发现它 - 不知何故,它会触发。

更新 我只是在USN期刊一捅,似乎不会得到你想要的东西无论是作为写入只有当文件被关闭的记录。 - >http://msdn.microsoft.com/en-us/library/aa363803(VS.85).aspx 我也发现一个USN-Viewer in C#http://social.msdn.microsoft.com/Forums/en/csharpgeneral/thread/c1550294-d121-4511-ac32-31551497f64e也许是有趣的阅读以及。

我还运行DiskMon以查看它是否实时获取更改。它没有,但我不知道这是否是有意的。但是,两者的问题在于它们需要管理权限才能运行。 所以我想你被FileSystemWatcher困住了。 (什么是你需要的反正更新,它不喜欢你可以阅读文件,而它的开放/被其他程序锁定。)

PS:我刚才注意到你是BugAid的开发,这让我意识到它只是最近 - 它看起来真棒:)

+0

感谢您的回答。在我的代码中,每次写入和刷新后都已经有Sleep(3000),所以FileSystemWatcher不应该有发送事件的任何问题。另外,从你发布的输出看来,似乎FSW确实没有发送/接收事件,直到流被关闭......我已经在我的代码中更正了DateTime的ToString以显示更好。很高兴你喜欢BugAid :)让我知道如果你有任何疑问! – VitalyB 2012-03-05 09:39:52

+0

呵呵,我觉得很傻,我忽略了这一点,猜想起床后读代码的第一件事情不是一个好主意。编辑:好吧,我现在看到你的意思。 – Brunner 2012-03-05 10:01:07