您的位置:首页 > 编程语言 > C语言/C++

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

2017-09-14 11:50 573 查看

 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,来存放上一次检测到的路径,再触发事件后就是判断是否与上一次的路径是否相同,如果不相同才去执行下面的步骤。

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

   
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: