FileSystemWatcher changed event (for “LastWrite”) is unreliable

喜你入骨 提交于 2019-12-09 01:01:51

问题


I am trying to get a notification when a file is updated on disk. I am interested in getting this notifications as soon as a flush occurs, yet, it seems that the FileSystemWatcher would only send an event when the stream opens or closes.

In the code below I am writing to a file and repeatedly flush the buffer to the disk. Yet, the FileSystemWatcher only notified me once in the beginning of the writes and once when they end.

Is there another way to get these notifications? Or should I use polling for that?

The code:

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

I've corrected the ToString function of the DateTime to show seconds. Here is the output with the code above:

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!

Thanks!


回答1:


It has nothing to do with the FileSystemWatcher. The watcher reacts to updates on the LastWrite attribute for the filesystem.

E.g. NTFS does not update the LastWrite on every write. The value is cached and only written when the stream is closed or at some other unspecified time. This document says

Timestamps are updated at various times and for various reasons. The only guarantee about a file timestamp is that the file time is correctly reflected when the handle that makes the change is closed. [...] The NTFS file system delays updates to the last access time for a file by up to 1 hour after the last access

I assume a similar caching applies for write




回答2:


I think one of your issues here is that all your writes get executed before the event gets a slice of that cpu-time. MSDN states

The Changed event is raised when changes are made to the size, system attributes, last write time, last access time, or security permissions of a file or directory in the directory being monitored.

I did a test and inserted Sleeps after each call to WriteData(...), what i got was

09:32] Watcher changed!

09:32] Watcher changed!

09:32] -----> Wrote data

09:32] -----> Wrote data

09:32] -----> Wrote data

09:32] -----> Wrote data

09:32] Watcher changed!

09:32] Watcher changed!

I guess this kind of proves that the even is fired right after you call Flush(), it's just a question of when the event-handler gets executed (and I assume it groups events as well). I don't know the specific needs of your project, but I wouldn't poll. Seems like a waste since FileSystemWatcher does what you want it to do in my opinion.

Edit: Ok, I guess my brain wasn't quite ready yet for thinking when I posted this. Your conclusion that it fires when you open and close the stream seems more logical and right. I guess I was looking for "prove" that it fires when you call flush and therefore found it - somehow.

Update I just had a poke at the USN-Journal and it seems that wont get you what you want either as it writes the record only when the file is closed. -> http://msdn.microsoft.com/en-us/library/aa363803(VS.85).aspx I also found a USN-Viewer in C# and http://social.msdn.microsoft.com/Forums/en/csharpgeneral/thread/c1550294-d121-4511-ac32-31551497f64e might be interesting to read as well.

I also ran DiskMon to see if it gets the changes in realtime. It doesn't, but I don't know if that's intentional or not. However, the problem with both is that they require admin-rights to run. So I guess you are stuck with FileSystemWatcher. (What is it you need the updates for anyway, it's not like you can read the file while it's open/locked by another program.)

ps: I just noticed you are a dev of BugAid, which I was made aware of it only recently - it looks awesome :)



来源:https://stackoverflow.com/questions/9563037/filesystemwatcher-changed-event-for-lastwrite-is-unreliable

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!