FileSystemWatcher事件多次触发的解决方法 (C++版)

 FileSystemWatcher

这篇文章是承接上一篇文章发布的,主要是解决使用FileSystemWatcher类时出现的多次检测到相同文件,还有FTP下载产物中间文件TMP的鉴别

1.使用时间戳

   我查了很多资料,其中有一个BACON的人发表了这么一篇文章:https://spin.atomicobject.com/2010/07/08/consolidate-multiple-filesystemwatcher-events/

 PS:C#的代码是这么写的:

using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;

namespace FileSystem
{
  public delegate void FileSystemEvent(String path);

  public interface IDirectoryMonitor
  {
    event FileSystemEvent Change;
    void Start();
  }

  public class DirectoryMonitor : IDirectoryMonitor
  {
    private readonly FileSystemWatcher m_fileSystemWatcher = 
      new FileSystemWatcher();
    private readonly Dictionary<string, DateTime> m_pendingEvents = 
      new Dictionary<string, DateTime>();
    private readonly Timer m_timer;
    private bool m_timerStarted = false;

    public DirectoryMonitor(string dirPath)
    {
      m_fileSystemWatcher.Path = dirPath;
      m_fileSystemWatcher.IncludeSubdirectories = false;
      m_fileSystemWatcher.Created += new FileSystemEventHandler(OnChange);
      m_fileSystemWatcher.Changed += new FileSystemEventHandler(OnChange);

      m_timer = new Timer(OnTimeout, null, Timeout.Infinite, Timeout.Infinite);
    }

    public event FileSystemEvent Change;

    public void Start()
    {
      m_fileSystemWatcher.EnableRaisingEvents = true;
    }

    private void OnChange(object sender, FileSystemEventArgs e)
    {
      // Don't want other threads messing with the pending events right now
      lock (m_pendingEvents)
      {
        // Save a timestamp for the most recent event for this path
        m_pendingEvents[e.FullPath] = DateTime.Now;

        // Start a timer if not already started
        if (!m_timerStarted)
        {
          m_timer.Change(100, 100);
          m_timerStarted = true;
        }   
      }
    }

    private void OnTimeout(object state)
    {
      List<string> paths;

      // Don't want other threads messing with the pending events right now
      lock (m_pendingEvents)
      {
        // Get a list of all paths that should have events thrown
        paths = FindReadyPaths(m_pendingEvents);

        // Remove paths that are going to be used now
        paths.ForEach(delegate(string path)
          {
            m_pendingEvents.Remove(path);
          });

        // Stop the timer if there are no more events pending
        if (m_pendingEvents.Count == 0)
        {
          m_timer.Change(Timeout.Infinite, Timeout.Infinite);
          m_timerStarted = false;
        }
      }

      // Fire an event for each path that has changed
      paths.ForEach(delegate(string path)
        {
          FireEvent(path);
        });
    }

    private List<string> FindReadyPaths(Dictionary<string, DateTime> events)
    {
      List<string> results = new List<string>();
      DateTime now = DateTime.Now;

      foreach (KeyValuePair<string, DateTime> entry in events)
      {
        // If the path has not received a new event in the last 75ms
        // an event for the path should be fired
        double diff = now.Subtract(entry.Value).TotalMilliseconds;
        if (diff >= 75)
        {
          results.Add(entry.Key);
        }
      }

      return results;
    }

    private void FireEvent(string path)
    {
      FileSystemEvent evt = Change;
      if (evt != null)
      {
        evt(path);
      }
    }
  }
}

2.使用静态私有成员

using namespace System;
using namespace msclr::interop;
using namespace System::IO;
using namespace System::Security::Permissions;
using namespace System::Runtime::InteropServices;
ref class FSEventHandler
{
private:
	static int count = 0;
	static time_t startTime = 0;
	static String ^ deforePath = "0";
	void OnChanged(Object^ source, FileSystemEventArgs^ e)
	{

		char* path = (char*)(Marshal::StringToHGlobalAnsi(e->FullPath)).ToPointer();
		String^Spath = marshal_as<String^>(path);
		if (deforePath != Spath)
		{
			startS12(path);
			deforePath = Spath;
		}
	}

public:
	/*启动检测*/
	int static run1(String ^ MonitorPath)
	{
		//创建一个FileSystemWatcher并设置它的属性.
		FileSystemWatcher^ fsWatcher = gcnew FileSystemWatcher();
		fsWatcher->Path = MonitorPath;

		//设置缓冲区大小1M,根据需求设置
		fsWatcher->InternalBufferSize = 1048576;

		//监听文件、目录、文件大小的改变
		fsWatcher->NotifyFilter = NotifyFilters::FileName | NotifyFilters::DirectoryName | NotifyFilters::Size;

		//监听子目录
		fsWatcher->IncludeSubdirectories = true;

		//添加事件处理程序
		FSEventHandler^ handler = gcnew FSEventHandler();
		fsWatcher->Changed += gcnew FileSystemEventHandler(
			handler, &FSEventHandler::OnChanged);

		//开始监听
		fsWatcher->EnableRaisingEvents = true;
		
		system("pause");//把父进程阻塞起来,防止负责检测的子进程死掉
		return 0;

	}
};

我大致介绍一下我的想法:

就是利用一个中间的变量tempStringPath,来存放上一次检测到的路径,再触发事件后就是判断是否与上一次的路径是否相同,如果不相同才去执行下面的步骤。

但是局限性就是不能用在同名文件覆盖,或者同名文件修改的项目中。

   

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ym影子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值