FileSystemWatcher报告网络共享上可用的文件,但找不到文件

时间:2017-11-18 13:15:38

标签: multithreading filesystemwatcher shared-directory windows-share

背景

我的服务器有一个包含4个子文件夹的共享文件夹\\Server\Share

  • OutboundFinal
  • OutboundStaging
  • InboundFinal
  • InboundStaging

所有文件夹都驻留在同一物理磁盘和分区上,不使用连接点。

我还有几个WinForms客户端(最多10个)写入和读取此共享的文件,每个客户端正在处理多个线程(最多5个)。客户端(最多50个线程)将文件放入\\Server\Share\OutboundStaging文件夹中。每个文件都有一个GUID的名称,因此没有覆盖。文件完全写入后,客户端会将其移动到\\Server\Share\OutboundFinal文件夹。在同一服务器上运行的Windows服务将获取它,删除它,处理它,然后将具有相同名称的文件写入\\Server\Share\InboundStaging文件夹。文件完全写入后,服务将其移至\\Server\Share\InboundFinal文件夹。

使用FileSystemWatcher.WaitForChanged(WatcherChangeTypes.Changed | WatcherChangeTypes.Created, timeOut);,每个WinForms客户端的每个线程监视此\\ Server \ Share \ InboundFinal文件夹 FileSystemWatcher.Filter设置为某个线程期望在\ Server \ Share \ InboundFinal文件夹中看到的文件的GUID文件名,因此FileSystemWatcher将等待,直到文件夹中显示特定文件。

我已经阅读了几个关于FileSystemWatcher行为不正常且没有报告UNC股票变化的SO问题。然而,对我来说并非如此。

我使用的代码如下所示:

    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;
    }

它是抛出异常的使用行。

问题

我认为只有具有正确GUID名称的文件位于\\Server\Share\InboundFinal文件夹中,fileWatcher.WaitForChanged才会继续。这正是FileSystemWatcher如何在本地文件夹上工作,而不是通过网络访问的文件共享(本地文件,甚至通过共享访问,也可以工作)。 FileSystemWatcher报告线程正在等待的文件位于FileSystemWatcher \\Server\Share\InboundFinal文件夹中。但是,当我尝试读取文件时,我得到一个FileNotFoundException。读取线程必须等待3-15秒才能读取文件。我尝试使用Read共享的FileStream打开文件。

什么可能导致这种行为?我该如何解决?理想情况下,只有在可以读取文件或发生超时时,FileSystemWatcher.WaitForChanged(WatcherChangeTypes.Changed | WatcherChangeTypes.Created, timeOut);才应继续执行。

1 个答案:

答案 0 :(得分:0)

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/

File open fails initially when trying to open a file located on a win2k8 share but eventually can succeeed

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

然后重启。