我昨晚发布的答案没有通过回归测试。我得到了混合的结果和文件系统观察程序的不同过滤器设置,它偶尔会错过不可接受的文件。有很多关于网络共享问题的文章,但我认为这意味着观察者正在观察映射到另一台计算机的网络共享,而不是被观察的目录本身就是运行服务的同一台机器上的网络共享。延迟可能是我的一些失误的一个因素,但即使在本地,该组件似乎也无法识别多点文件名。
由于这是一项服务,我们已经有了一种方法来检测服务启动时已经存在的任何文件。这种方法有效并且不依赖于组件。所以最优雅的解决方案是简单地将代码放在计时器上。以下是该类的相关部分(即,此代码段并非设计为可复制/粘贴,仅用于展示我如何解决问题)。不要让 FTP 绰号让您偏离正题——它实际上只是在查看一个可能映射到也可能不映射到 FTP 服务器的共享文件夹。
using System.Collections.Generic;
using Timer = System.Timers.Timer;
public partial class VsiFtpManager : ServiceBase
{
private Timer _searchTimer;
private Queue<string> _filesToProcess;
private string _ftpRoot; //this is set elsewhere from the registry
protected override void OnStart(string[] args)
{
//process any files that are already there when the service starts
LoadExistingFtpFiles();
//Handle new files
_searchTimer = new Timer(10000);
_searchTimer.Elapsed += LoadExistingFtpFiles;
}
//convenience overload to allow this to handle timer events
private void LoadExistingFtpFiles(object source, ElapsedEventArgs evtArgs)
{
LoadExistingFtpFiles();
}
private void LoadExistingFtpFiles()
{
_searchTimer.Stop();
var di = new DirectoryInfo(_ftpRoot);
FileInfo[] fileInfos = di.GetFiles("*.*", SearchOption.AllDirectories);
foreach (FileInfo fi in fileInfos.Where(fi => fi != null))
{
if (fi.Extension != "processed" && !_filesToProcess.Contains(fi.FullName))
{
LogHelper.BroadcastLogMessage("INFO: File " + fi.Name + " was uploaded.", EventLogEntryType.Information);
_filesToProcess.Enqueue(fi.FullName);
LogHelper.BroadcastLogMessage("File received: " + fi.Name, EventLogEntryType.Information);
}
}
_searchTimer.Start();
}
}
您看不到的部分超出了我的问题范围,它本质上是针对队列 _filesToProcess 运行的协同程序,它处理文件然后将它们重命名为具有 .processed 的扩展名。
所以我的最终答案是:我的研究,通过自动回归测试证实,表明文件系统观察器对我的用例不可靠,这需要我处理复制到文件夹中的文件。其中一些文件将来自 Unix 系统,因此可能具有非 Windows 文件名。.net 附带的文件系统观察程序组件无法可靠地检测名称中带有多个点的 unix 样式文件名称。
我用一个简单的轮询机制替换了文件系统观察程序。执行速度明显较慢但可靠,这是我的主要目标。整体解决方案减少了我的代码行数,尽管微不足道,并删除了我在服务设计表面上的唯一组件,由于我自己可能有特殊的偏好,我认为这两者都有好处。