Файл отчетов FileSystemWatcher доступен на общем сетевом ресурсе, но файл не найден
ФОН
У меня есть сервер с общей папкой \\Server\Share
с 4 подпапками:
- OutboundFinal
- OutboundStaging
- InboundFinal
- InboundStaging
Все папки находятся на одном физическом диске и разделе, точки соединения не используются.
У меня также есть несколько клиентов WinForms (до 10), которые пишут и читают файлы в этот общий ресурс, каждый клиент работает в нескольких потоках (до 5). Файлы регистрируются клиентами (всего до 50 потоков) в \\Server\Share\OutboundStaging
папка. Каждый файл имеет имя GUID, поэтому перезаписи нет. Как только файл полностью записан, клиент перемещает его в \\Server\Share\OutboundFinal
папка. Служба Windows, работающая на том же сервере, подберет его, удалит, обработает, а затем запишет файл с тем же именем в \\Server\Share\InboundStaging
папка. Как только файл полностью записан, он перемещается в \\Server\Share\InboundFinal
папка сервисом.
Эта папка \\Server\Share\InboundFinal контролируется каждым потоком каждого клиента WinForms с помощью FileSystemWatcher.WaitForChanged(WatcherChangeTypes.Changed | WatcherChangeTypes.Created, timeOut);
FileSystemWatcher.Filter
устанавливается в имя файла GUID файла, который определенный поток ожидает увидеть в папке \ Server \ Share \ InboundFinal, поэтому FileSystemWatcher ожидает, пока в папке не отобразится определенный файл.
Я прочитал несколько вопросов о FileSystemWatcher
ведет себя хаотично и не сообщает об изменениях в акциях UNC. Однако это не так для меня.
Код, который я использую, выглядит следующим образом:
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;
}
Это строка с использованием исключения.
ЭТА ПРОБЛЕМА
Я хотел бы предположить, что fileWatcher.WaitForChanged будет продолжаться, только если файл с правильным именем GUID находится в \\Server\Share\InboundFinal
папка. Именно так FileSystemWatcher работает с локальными папками, но не с общими файловыми ресурсами, доступ к которым осуществляется через сеть (локальные файлы, даже доступные через общий ресурс, также обычно работают). FileSystemWatcher сообщает, что файл, который ожидает поток, находится в FileSystemWatcher \\Server\Share\InboundFinal
папка. Однако когда я пытаюсь прочитать файл, я получаю исключение FileNotFoundException. Поток чтения должен ждать 3-15 секунд, прежде чем файл может быть прочитан. Я пытаюсь открыть файл с FileStream с Read
обмен.
Что может вызвать такое поведение? Как мне обойти это? В идеале FileSystemWatcher.WaitForChanged(WatcherChangeTypes.Changed | WatcherChangeTypes.Created, timeOut);
следует продолжить выполнение, только если файл может быть прочитан или истекло время ожидания.
1 ответ
FileSystemWatcher имеет плохую репутацию, но на самом деле это не так уж плохо...
1.)
Ваш пример кода не компилируется. Я попробовал это:
FileSystemWatcher fileWatcher = new FileSystemWatcher();
fileWatcher.Path = "X:\\temp";
fileWatcher.Filter = "test.txt";
fileWatcher.EnableRaisingEvents = true;
fileWatcher.IncludeSubdirectories = false;
var res = fileWatcher.WaitForChanged(WatcherChangeTypes.Changed |
WatcherChangeTypes.Created, 20000);
if (!res.TimedOut)
{
FileInfo fi = new FileInfo(Path.Combine(fileWatcher.Path, res.Name));
using (FileStream stream = fi.Open(FileMode.Open, FileAccess.Read, FileShare.Read))
{
byte[] buf = new byte[stream.Length];
stream.Read(buf, 0, (int)stream.Length);
}
Console.WriteLine("read ok");
}
else
{
Console.WriteLine("time out");
}
Я проверил это, где X: SMB доля. Работало без проблем (для меня см. Ниже).
Но:
Вы должны открыть / прочитать файл с повторными попытками (спящий в течение 100 мс после каждого неудачного открытия). Это связано с тем, что вы можете столкнуться с ситуацией, когда FileSystemWatcher обнаружит файл, но перемещение (или другая операция записи) еще не завершено, поэтому вам придется подождать, пока создание / перемещение файла действительно не будет готово.
Или вы ожидаете не "настоящий" файл, а файл флага, который задача перемещения файла создает после закрытия "реального" файла.
2.)
Может быть, задача перемещения не закрыла файл правильно?
3.)
Несколько лет назад у меня было несколько инструментов (написанных на Perl), в которых один скрипт создавал файл флага, а другой ждал его.
У меня были некоторые неприятные проблемы с акцией SMB 2. Я узнал, что это связано с кэшированием SMB.
Увидеть
https://bogner.sh/2014/10/how-to-disable-smb-client-side-caching/
При открытии файла, находящегося на общем ресурсе win2k8, сначала происходит сбой
https://technet.microsoft.com/en-us/library/ff686200.aspx
Попробуйте это (на клиенте):
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\LanmanWorkstation\Parameters]
"DirectoryCacheLifetime"=dword:00000000
"FileNotFoundCacheLifetime"=dword:00000000
Сохраните это как disablecache.reg и запустите regedit disablecache.reg
Затем перезагрузите компьютер.