使用 Visual Studio 2019 将 FileSystemWatcher 作为 Windows 服务

Posted

技术标签:

【中文标题】使用 Visual Studio 2019 将 FileSystemWatcher 作为 Windows 服务【英文标题】:FileSystemWatcher as a Windows Service using Visual Studio 2019 【发布时间】:2021-09-19 09:46:05 【问题描述】:

所以,我创建了一个 Windows 服务,我在其中使用 FileSystemWatcher 来查看不同的目录。每次检测到更改的文件时,我都会将它们复制到不同的目录中,以便以后使用它们。

当我将程序作为控制台应用程序运行时,这完美运行

当我将它作为服务运行时,我可以正确启动和停止该服务,但它不会检测到任何类型的事件。 我尝试调试我的服务,发现错误来自于我没有停止FileSystemWatcher

对于我的控制台应用程序,我有 Watch() 方法的代码:

    public void Watch()
    
        using (FileSystemWatcher watcher = new FileSystemWatcher($"C:\\Users\\wost\\AppData\\Roaming\\Sublime", _ext))
        
            watcher.NotifyFilter = NotifyFilters.LastAccess
                                 | NotifyFilters.LastWrite
                                 | NotifyFilters.FileName
                                 | NotifyFilters.DirectoryName;

            watcher.IncludeSubdirectories = true;
            // Add event handlers.
            watcher.Changed += OnChanged;
            watcher.Created += OnChanged;
            watcher.Deleted += OnChanged;
            watcher.Renamed += OnRenamed;

            // Begin watching.
            watcher.EnableRaisingEvents = true;

            // Wait for the user to quit the program.
            Console.WriteLine("Press 'q' to quit the sample.");
            while (Console.Read() != 'q') ;
        
    

所以,如果用户按“q”,我会停止程序。

对于我的 Windows 服务,我有 Watch() 方法的代码:

 public void Watch()
    
        using (FileSystemWatcher watcher = new FileSystemWatcher($"C:\\Users\\lashi\\AppData\\Roaming\\Sublime Text 3", _ext))
        
            watcher.NotifyFilter = NotifyFilters.LastAccess
                                 | NotifyFilters.LastWrite
                                 | NotifyFilters.FileName
                                 | NotifyFilters.DirectoryName;

            watcher.IncludeSubdirectories = true;
            // Add event handlers.
            watcher.Changed += OnChanged;
            watcher.Created += OnChanged;
            watcher.Deleted += OnChanged;
            watcher.Renamed += OnRenamed;

            // Begin watching.
            watcher.EnableRaisingEvents = true;

        
    

所以,在这里我根本没有停止FileSystemWatcher,因为我没有与用户直接交互,我不知道如何停止它。你能帮我找到解决办法吗?

这些是OnStart()OnStop() 方法:

public partial class Service1 : ServiceBase

    Watcher w;
    
    public Service1()
    
        InitializeComponent();
    

    protected override void OnStart()
    
        w = new Watcher($"C:\\EMMC_CACHE\\expt1-log", $"C:\\EMMC_CACHE\\expt1-file", "lashi");
        w.Watch();
    

    protected override void OnStop()
    
        DirectoryInfo dir = new DirectoryInfo(@"C:\Users\wost\Desktop\FILES");
        int count = dir.GetFiles().Length;
        // TEST
        if (count == 0)
        
            StreamWriter writer = new StreamWriter(@"C:\Users\wost\Desktop\Notes.txt");
            writer.WriteLine("Service is stopped at: " + DateTime.Now);
            writer.Close();
        
    

【问题讨论】:

我认为问题在于,在Watch 方法末尾的Windows 服务中,Dispose FileSystemWatcher 实例因为using 块退出。要做的第一件事是删除此处的 using 块,第二件事是将观察者声明为类的 field。第三个是实现Dispose 模式。但首先要做的事情...... 在您不退出的控制台版本中,您有一个“等待循环”,例如 while (Console.Read() != 'q') ; @lidqy 谢谢你的回答!我试图摆脱'using'语句,但我仍然得到相同的结果。 @MickyD 谢谢你的回答!是的,我已经更改了帐户,但得到了相同的结果。 @MickyD 致企业管理员,因为我使用的是企业 PC。 【参考方案1】:

我认为你需要让观察者成为一个领域,而不是过早地处置它。我没有测试这段代码,但我认为你在“Watch”中看到了相关的变化......

internal class Watcher : IDisposable 

    private FileSystemWatcher _watcher;
    private string _directoryPath;  
    private string _ext;
    
    internal Watcher (string directoryPath, string ext) 
            _directoryPath = directoryPath;
            _ext = ext;
    
    ~Watcher () 
        Dispose();
    
    public void Watch()
    
        Dispose();
        
        _watcher = new FileSystemWatcher(_directoryPath, _ext);
        
        _watcher.NotifyFilter = NotifyFilters.LastAccess
                             | NotifyFilters.LastWrite
                             | NotifyFilters.FileName
                             | NotifyFilters.DirectoryName;

        _watcher.IncludeSubdirectories = true;
        // Add event handlers.
        _watcher.Changed += OnChanged;
        _watcher.Created += OnChanged;
        _watcher.Deleted += OnChanged;
        _watcher.Renamed += OnRenamed;

        // Begin watching.
        _watcher.EnableRaisingEvents = true;
    
    
     public void Dispose() 
        try 
           _watcher?.Dispose();
         catch 
           ;
        
        _watcher = null;
     
     //FSW event handlers...


【讨论】:

噢!你打我! +1 :) @lidqy 感谢您抽出宝贵时间提出此解决方案!我刚刚尝试过,但我仍然有相同的结果!我不明白错误来自哪里。 AT WillWost 嗯。正如@MickyD 指出的那样,它可能与服务运行的用户上下文及其 fs 访问权限有关。或者,但这只是一个猜测,观察者的另一个实例仍在运行(我只是假设这可能会导致麻烦,完全是虚构的)。或者当然,您执行的真实代码 /whic 肯定与您发布的令牌不同并且更复杂)还有另一个问题,论坛不可见。 @lidqy 显然,重试后,您的解决方案工作正常。谢谢你! 感谢您的反馈,@WillWost

以上是关于使用 Visual Studio 2019 将 FileSystemWatcher 作为 Windows 服务的主要内容,如果未能解决你的问题,请参考以下文章

Visual Studio 2019 C# 断点调试 & 凯撒密码,单码密码实现

关闭 Visual Studio 动画

使用 Visual Studio 2019 将 FileSystemWatcher 作为 Windows 服务

如何让 Visual Studio 中的 Intel Parallel 运行 .f77、.f9​​5 等?

visual studio 2015怎么破解

将 DCMTK 与 Visual Studio 一起使用时出现链接器错误 LNK2019