Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

FileSystemWatcher does not report changes in a locked file

I'm monitoring a folder using a FileSystemWatcher like this:

watcher = new FileSystemWatcher(folder);
watcher.NotifyFilter = NotifyFilters.Size;
watcher.Changed += changedCallback;

When I open a new file in notepad in that folder and save it, I get a notification. If I keep writing and then I save, I get a notification. If I close the file with saving it, I get a notification. Exactly what I wanted.

However, it turns out that if I create a file in that folder and I set its sharing mode to FileShare.Read, and then I write to it, I will not get any notifications until the file is closed. Another workaround is to open the file (e.g. in Notepad), which apparently causes its state to be updated, and then my monitoring application gets the notification. Yet another workaround is a refresh I can do in Windows Explorer, which again causes the file state to be updated.

Interestingly, if I look at Windows Explorer while I make the changes, I notice that:

  1. If the file is shared for reading & writing, its size will be updated immediately in Windows Explorer as soon as I save it.
  2. If the file is shared for reading only, its size will NOT be update immediately in Windows Explorer, unless I manually refresh the window.

So it seems that my monitoring application shares the same behavior as Windows Explorer. I was thinking about running a thread that will just scan the files in the folder, but I'm wondering if there's anything more elegant to be done in this case.

BTW, I'm using Win7 and I'm not sure that this problem happens on other Windows versions as well.

Thanks!

EDIT: Using ReadDirectoryChanges in C++ got me the same exact results. Implementing the thread I was talking about earlier didn't help as well. I'm wondering what is F5 in Windows Explorer actually doing, because it does cause the change to be reported.

like image 934
Eldad Mor Avatar asked Aug 22 '10 08:08

Eldad Mor


2 Answers

The solution to the problem is not to open the files, but to actually READ from them. It's enough to read even one byte, and the Windows cache mechanism will write the contents of the file to the disk, thus allowing you to read them.

I ended up implementing a thread that went over all the files, opened them and read a byte from them. This caused them to change, and triggered the event in the FileSystemWatcher object.

The reason that Windows Explorer F5 works as well, is that Windows actually reads the contents of the file in order to show some extended contents (e.g., thumbnails). Once the file is being read, the cache first writes to the disk, triggering the event in the FSW.

like image 162
Eldad Mor Avatar answered Sep 29 '22 23:09

Eldad Mor


Yes, Explorer uses the exact same API as FileSystemWatcher uses. There's just one, ReadDirectoryChangesW() as you found out.

What you found strongly suggest that Win7 is optimizing the disk write that would be needed to update the directory entry for the file. Delaying it until the last possible moment, when the file is closed. There's an interesting correlation between this observation and a critical bug that a user discovered in the RTM version of Win7. The update sometimes doesn't happen at all. The bug strikes randomly but infrequently, I've seen this myself just once on my machine. Knowingly anyway.

The details are in this thread (beware of very slow server). This still fails today with all Win7 updates applied.

Well, interesting tidbit but not really germane to your question. You do need to alter your code to accommodate the OS works.

like image 42
Hans Passant Avatar answered Sep 29 '22 22:09

Hans Passant