I'm watching a directory by calling ReadDirectoryChangesW
synchronously. When a new file is available, I try to access it immediately with CreateFile
with GENERIC_READ
and FILE_SHARE_READ
, but this gives me ERROR_SHARING_VIOLATION
. The process that put the file in the watched directory does not finish writing by the time I try to read it.
Is there any way to reliably wait until the file is available for reading? I can put the method into a loop like the one below, but I'm hoping there's a better way.
while ((hFile = CreateFile (path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
{
if (GetLastError() == ERROR_SHARING_VIOLATION)
Sleep (500);
else
break; // some other error occurred
}
if (hFile == INVALID_HANDLE_VALUE)
{
// deal with other error
return 0;
}
ReadFile (...);
If you know something about how the file is created, maybe wait until the file stops growing for X seconds, or wait until a sentinel file is deleted. Or sense the state of the program which creates them.
There's no user-mode API for notifications on a closed file that I'm aware of. The loop you've proposed is really probably the best way. The only other thing you could do would be to watch for
CloseFile
in a filter driver ala Process Monitor, but yuck...I don't think there is a notification for the kind of event you're looking for, but as an improvement, I'd suggest progressive delays. This way you will get fast response times for stuff like a drag/drop and won't hog the CPU with a tight loop if the user keeps the file open for an hour in Excel.
As @Matt Davis said, there is unfortunately no user-mode API but there is a workaround that depending on your use-case (I've written mine below) may do just what you want.
What worked for me in the past was registering for
FILE_NOTIFY_CHANGE_LAST_WRITE
instead ofFILE_NOTIFY_CHANGE_FILE_NAME
when callingReadDirectoryChangesW
:The last write time gets updated as soon as the owning process closes the handle after creating the file and writing to it.
My use-case was one process that received HTTP-requests via TCP/IP and wrote the HTTP-body into a directory, where another process picked it up as soon as the receiving process was finished writing (and consequently closing the handle) it. The http-server was the only process that wrote to that directory, so I could rely on the create-write-close pattern.