BACKGROUND
I have a server that has a shared folder \\Server\Share
with 4 subfolders:
- OutboundFinal
- OutboundStaging
- InboundFinal
- InboundStaging
All folders reside on the same physical disk and partition, no junction points used.
I also have several WinForms clients (up to 10) that write and read files to this share, each client is working on multiple threads (up to 5). Files are witten by clients (up to 50 threads altogether) into the \\Server\Share\OutboundStaging
folder. Each file has the name of a GUID, so there's no overwriting. Once a file is completely written, it is moved by the client to the \\Server\Share\OutboundFinal
folder. A Windows service running on the same server will pick it up, delete it, process it, then writes the file with the same name into the \\Server\Share\InboundStaging
folder. Once the file is completely written, it is moved to the \\Server\Share\InboundFinal
folder by the service.
This \\Server\Share\InboundFinal folder is monitored by each thread of each WinForms client using a FileSystemWatcher.WaitForChanged(WatcherChangeTypes.Changed | WatcherChangeTypes.Created, timeOut);
The FileSystemWatcher.Filter
is set to the GUID filename of the file a certain thread expects to see in the \Server\Share\InboundFinal folder, so the FileSystemWatcher waits until a specific file is shown in the folder.
I have read several SO questions about FileSystemWatcher
behaving erratically and not reporting changes on UNC shares. This is however not the case for me.
The code I use looks like this:
FileSystemWatcher fileWatcher = new FileSystemWatcher();
fileWatcher.Path = InboundFinalFolder;
fileWatcher.Filter = GUIDFileName; // contains full UNC path AND the file name
fileWatcher.EnableRaisingEvents = true;
fileWatcher.IncludeSubdirectories = false;
var res = fileWatcher.WaitForChanged(WatcherChangeTypes.Changed | WatcherChangeTypes.Created, timeOut);
if (!fileWatcher.TimedOut)
{
using (FileStream stream = fi.Open(FileMode.Open, FileAccess.Read, FileShare.Read)) {
byte[] res = new byte[stream.Length];
stream.Read(res, 0, stream.Length);
return res;
}
It's the using line that throws the exception.
THE PROBLEM
I would assume that the fileWatcher.WaitForChanged would go on only if the file with the proper GUID name is in the \\Server\Share\InboundFinal
folder. This is exactly how FileSystemWatcher works on local folders, but not with file shares accessed over the network (local files, even accessed via a share, also tend to work). FileSystemWatcher reports that the file the thread is waiting for is in the FileSystemWatcher \\Server\Share\InboundFinal
folder. However, when I try to read the file, I get a FileNotFoundException. The reading thread has to wait 3-15 seconds before the file can be read. I try to open the file with a FileStream with Read
sharing.
What could cause this behavior? How do I work around it? Ideally the FileSystemWatcher.WaitForChanged(WatcherChangeTypes.Changed | WatcherChangeTypes.Created, timeOut);
should only continue execution if the file can be read or timeout happens.