c# FileSystemWatcher - 每隔几秒引发数百个不需要的过度事件

c# FileSystemWatcher - Raising hundreds of unwanted excessive events every several seconds

我正在使用 FileSystemWatcher class,我需要它来监控我插入的闪存驱动器,以查找从任何地方创建或粘贴的文件。我每 2 秒刷新一次插入的驱动器列表(如果有任何新插入的驱动器到达),然后设置 FileSystemWatcher.EnableRaisingEvents = true,然后在 2 秒后我将其设置为 "false",然后再次刷新插入的驱动器列表等

当刷新间隔为2秒时,情况如下:

  1. 程序运行 1 秒,我将文件粘贴到闪存驱动器 - FSW 引发了一个 "Created" 事件。
  2. 程序运行了 3 秒,我将文件粘贴到闪存驱动器 - FSW 引发了两个 "Created" 事件。
  3. 程序运行了 5 秒,我将文件粘贴到闪存驱动器 - FSW 引发了三个 "Created" 事件。
  4. 该程序运行了几分钟,我将文件粘贴到闪存驱动器 - FSW 引发了一百(大约)"Created" 个事件。

但是!当刷新间隔为30秒时,情况如下:

  1. 程序运行 1 秒,我将文件粘贴到闪存驱动器 - FSW 引发了一个 "Created" 事件。
  2. 程序运行了 3 秒,我将文件粘贴到闪存驱动器 - FSW 引发了一个 "Created" 事件。
  3. 程序运行了 40 秒,我将文件粘贴到闪存驱动器 - FSW 引发了两个 "Created" 事件。

很明显,问题在于 FileSystemWatcher 没有正确清除自身,并且 "not-happened-events" 以某种方式在其中累积,然后当 "Created" 事件时它们一起出现真的发生了。

有必要保持较低的刷新间隔(大约 2-3-5 秒)。我不能提高到几分钟。

请帮忙。我坚持了六个小时。谢谢。对不起我的英语,它不是母语。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Management;
using System.Diagnostics;
using System.Collections.Specialized;
using System.Runtime.InteropServices;
using System.Threading;

private static FileSystemWatcher watcher1 = new FileSystemWatcher();

private static DriveInfo[] GetDrivesList()
    {
        DriveInfo[] DriveList = DriveInfo.GetDrives();
        return DriveList;
    }

static bool IsFileLocked(FileInfo file)
    {
        FileStream stream = null;

        if (is_directory == false)
        {
            try
            {
                stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None);
            }
            catch (IOException)
            {
                return true;
            }
            finally
            {
                if (stream != null)
                    stream.Close();
            }
        }

        return false;
    }

    static void OnChanged(Object source, FileSystemEventArgs e)
    {
        FileInfo fileInfo = new FileInfo(e.FullPath);
        FileInfo fileInfo2 = new FileInfo(@"D:\Shadow Copies.log");

        if (Convert.ToString(e.ChangeType) == "Created")
        {
            Console.WriteLine("File: {0} has been {1}", e.FullPath, e.ChangeType);
            file_copied = false;

            int length = Convert.ToString(e.FullPath).Length;
            String Path = "";
            String FileName = "";
            for (int i = length - 1; i >= 0; i--)
            {
                if (Convert.ToString(e.FullPath)[i] != '\')
                {
                    Path += Convert.ToString(e.FullPath)[i];
                }
                else
                {
                    break;
                }
            }
            for (int i = Path.Length - 1; i >= 0; i--)
            {
                FileName += Path[i];
            }

            for (int i = FileName.Length - 1; i >= 0; i--)
            {
                if (FileName[i] == '.')
                {
                    is_directory = false;
                    break;
                }
            }

            string path = Convert.ToString(e.FullPath);

            while (IsFileLocked(fileInfo) == true)
            {
                Thread.Sleep(100);
                Console.WriteLine("Retrying in 1 sec...");
            }

            ProcessStartInfo psi = new ProcessStartInfo();
            psi.CreateNoWindow = true;
            psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
            psi.FileName = "cmd.exe";
            psi.Arguments = @"/c xcopy " + path + @" D:\ShadowCopies\ /s /y";
            Process proc = Process.Start(psi);

            file_copied = true;
            Console.WriteLine("File: {0} has been Copied", e.FullPath);
            DateTime datetime = DateTime.Now;

            CandidateLine = e.FullPath;
            write_to_log = String.Format("{0} File: {1} has been Copied\r\n", datetime.ToString(), e.FullPath);
            if (CandidateLine == LastLineWritten)
                return;
            while (IsFileLocked(fileInfo2) == true)
            {
                Thread.Sleep(100);
                Console.WriteLine("Retrying...");
            }
            File.AppendAllText(@"D:\Shadow Copies.log", write_to_log);
            LastLineWritten = CandidateLine;

            is_directory = true;

            ProcessStartInfo psi2 = new ProcessStartInfo();
            psi2.CreateNoWindow = true;
            psi2.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
            psi2.FileName = "cmd.exe";
            psi2.Arguments = "/c for /d %F in (D:\ShadowCopies\*) do rd /s /q %F";
            Process proc2 = Process.Start(psi2);
        }
    }

private static void WatchersInitialize()
    {
        DriveInfo[] DriveList = GetDrivesList();
        string[] DriveListArray = new string[DriveList.Length - 1];

        for (int i = 0; i < DriveListArray.Length; i++)
        {
            DriveListArray[i] = DriveList[i + 1].Name;
        } 

            watcher1.IncludeSubdirectories = true;
            watcher1.Path = DriveListArray[drive_position];
            watcher1.NotifyFilter = NotifyFilters.Attributes | NotifyFilters.CreationTime |
            NotifyFilters.DirectoryName | NotifyFilters.FileName |
            NotifyFilters.LastWrite | NotifyFilters.Security | NotifyFilters.Size;
            watcher1.Changed += new FileSystemEventHandler(OnChanged);
            watcher1.Created += new FileSystemEventHandler(OnChanged);
            watcher1.EnableRaisingEvents = true;
    return 0;
 }

static void Main(string[] args)
    {
        while (true)
        {
            watcher1.EnableRaisingEvents = false;
            watcher2.EnableRaisingEvents = false;
            watcher3.EnableRaisingEvents = false;
            watcher4.EnableRaisingEvents = false;
            watcher5.EnableRaisingEvents = false;
            WatchersInitialize();
            Thread.Sleep(2000);
        }
    }

在附加事件处理程序的位置我认为您应该先删除它们,以确保您不会加倍处理正在触发的事件。

watcher1.Changed -= new FileSystemEventHandler(OnChanged);
watcher1.Created -= new FileSystemEventHandler(OnChanged);
watcher1.Changed += new FileSystemEventHandler(OnChanged);
watcher1.Created += new FileSystemEventHandler(OnChanged);

您应该初始化一次观察器并订阅一次事件处理程序,而不是在无限循环中初始化同一个观察器,休眠 2 秒。在您的初始化块中,您不断为更改和创建的事件添加偶数处理程序。由于这些是 watcher 的相同物理实例,您只是在循环无限循环时一个接一个地累积事件处理程序回调。

这很可能是您的事件触发数百次的原因,因为您在每次迭代中都越来越多地订阅同一事件。

您需要在 while 循环之外接听电话 WatchersInitialize();