停止 FileSystemWatcher 后运行另一段代码

Posted

技术标签:

【中文标题】停止 FileSystemWatcher 后运行另一段代码【英文标题】:Run another piece of code after stopping FileSystemWatcher 【发布时间】:2021-09-11 00:23:30 【问题描述】:

我在 C# 中有一个FileSystemWatcher 代码,它检测已更改其内容的文件,然后将这些文件复制到指定目录(C:\Users\wost\Desktop\Data\files)。复制文件后,FileSystemWatcher 停止后,我想加密这些文件,我想在同一个程序中执行此操作。 所以我在主程序中有如下代码:

Watcher w = new Watcher(lexpt, fexpt, userName);
w.Watch();
// Function which encrypts the files
Encryption.EncryptFiles(@"C:\Users\wost\Desktop\Data\files");

这不起作用,因为FileSystemWatcher 永远不会停止,除非我退出程序。所以,我决定使用一个全局变量Global.serviceRunning,如下面的代码所示,它会阻止FileSystemWatcher 在指定目录中观看:

public void Watch()

    FileSystemWatcher watcher;
    using (watcher = new FileSystemWatcher(
        $"C:\\Users\\wost\\AppData\\Roaming\\Sublime Text 3", _ext))
    

        // Watch for changes in LastAccess and LastWrite times, and
        // the renaming of files or directories.
        watcher.NotifyFilter = NotifyFilters.LastAccess
                             | NotifyFilters.LastWrite
                             | NotifyFilters.FileName
                             | NotifyFilters.DirectoryName;

        // Only watch text files.
        // watcher.Filter = "*.txt";
        watcher.IncludeSubdirectories = true;
        // Add event handlers.
        watcher.Changed += OnChanged;
        watcher.Created += OnChanged;
        watcher.Deleted += OnChanged;
        watcher.Renamed += OnRenamed;

        // Begin watching.
        watcher.EnableRaisingEvents = true;
        //GLOBAL VARIABLE
        while (Global.serviceRunning == true) ;
    

我曾尝试在主程序中将此全局变量的值更改为false,但它不起作用。你能帮我找到一种方法来停止FileSystemWatcher,然后加密给定目录中的文件吗?

【问题讨论】:

“FileWatcher 永远不会停止,除非我退出程序” -- 嗯?为什么不直接将EnableRaisingEvents 设置回false?或者,如果您不想在禁用 FileSystemWatcher 对象后再次使用它,只需调用其 Dispose() 方法即可。当然,像while (Global.serviceRunning == true) ; 这样的代码应该从不被使用;这将占用整个 CPU 内核而没有任何用处。但完全不清楚为什么您不只是使用记录在案的正常机制来控制FileSystemWatcher 对象。 @PeterDuniho 谢谢你的回答!这是我第一次使用 FileSystemWatcher,我不太了解它是如何工作的。 @PeterDuniho 你能告诉我我需要在哪里将 EnableRaisingEvents 设置为 false,是在主程序中还是在方法 Watch() 中?谢谢! “我需要在哪里将 EnableRaisingEvents 设置为 false” - 您需要在执行代码时知道不再需要的地方设置它观察文件系统事件。您未能在帖子中解释您的场景的这一方面,因此无法将您指向代码中的确切位置。我怀疑它应该使用Watch() 方法。更有可能的是,在一个事件处理程序中,您知道您已经看到了您正在等待看到的任何内容,并且可以禁用 FileSystemWatcher 对象。 @PeterDuniho 我很抱歉。我以为很清楚。我不想在指定的时刻停止 FileSystemWatcher。我只是想在一段时间后停止它,这样我就可以给它足够的时间来寻找变化。我可以这样做吗?谢谢! 【参考方案1】:

您可以尝试取消相关事件以停止 FileSystemWatcher。

代码:

 static void Stop()
        
            watcher.EnableRaisingEvents = false;

            watcher.Changed -=new FileSystemEventHandler(OnChanged);
            watcher.Created -= new FileSystemEventHandler(OnChanged);
            watcher.Deleted -= new FileSystemEventHandler(OnChanged);
            watcher.Renamed -= new RenamedEventHandler(OnRenamed);
            watcher.Dispose();
        

我在控制台应用中进行了测试。

完整代码:

class Program
    
        static FileSystemWatcher watcher= new FileSystemWatcher();
        public static void Main(string[] args)
        
            watcher.Path = "E:\\Example";
            watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite |
                   NotifyFilters.FileName | NotifyFilters.DirectoryName;
            watcher.Filter = "*.txt";
            watcher.Changed += new FileSystemEventHandler(OnChanged);
            watcher.Created += new FileSystemEventHandler(OnChanged);
            watcher.Deleted += new FileSystemEventHandler(OnChanged);
            watcher.Renamed += new RenamedEventHandler(OnRenamed);
            watcher.EnableRaisingEvents = true;
            Console.WriteLine("Press\'q\' to stop the watcher.");
            while (Console.ReadLine()=="q")
            
                Stop();
            ;


            Console.ReadKey();
        

        static void Stop()
        
            watcher.EnableRaisingEvents = false;

            watcher.Changed -=new FileSystemEventHandler(OnChanged);
            watcher.Created -= new FileSystemEventHandler(OnChanged);
          
            watcher.Deleted -= new FileSystemEventHandler(OnChanged);
            watcher.Renamed -= new RenamedEventHandler(OnRenamed);
            watcher.Dispose();
        
        public static void OnChanged(object sender, FileSystemEventArgs e)
        
            Console.WriteLine("file:" + e.FullPath + "" + e.ChangeType);
        
        public static void OnRenamed(object sender, RenamedEventArgs e)
        
            Console.WriteLine("Fi]e:0 renamed to1", e.OldFullPath, e.FullPath);
        
    

【讨论】:

【参考方案2】:

正如其他人指出的in the comments,FileSystemWatcher.EnableRaisingEvents 属性是您应该使用的机制,以便激活或停用FileSystemWatcher 组件对目标目录的监视。

请注意,尽管在 ThreadPool 上引发了 FileSystemWatcher 事件,但内部机制使得在停用组件后无法调用处理程序。但是,当您将EnableRaisingEvents 设置为false 时,任何已经运行的处理程序都不会被中止。因此,您应该考虑到,在监控停用之后,某些文件可能会在后台继续被复制。

【讨论】:

以上是关于停止 FileSystemWatcher 后运行另一段代码的主要内容,如果未能解决你的问题,请参考以下文章

用FileSystemWatcher对象监控C#目录改变

FileSystemWatcher - 在删除时,复制一个文件

C# FileSystemWatcher - 多个事件

FileSystemWatcher 在功能后不会触发 [重复]

FileSystemWatcher 在作为 Release 运行时无法从两个目录获取事件

FileSystemWatcher 事件未在 WPF 应用程序中触发