FileSystemWatcher
// <https://msdn.microsoft.com/zh-cn/library/chzww271.aspx>
// monitor_fs.cpp
// compile with: /clr
#using <system.dll>
using namespace System;
using namespace System::IO;
ref class FSEventHandler
{
public:
void OnChanged (Object ^source, FileSystemEventArgs ^e)
{
Console::WriteLine("File: {0} {1}",
e->FullPath, e->ChangeType);
}
void OnRenamed(Object ^source, RenamedEventArgs ^e)
{
Console::WriteLine("File: {0} renamed to {1}",
e->OldFullPath, e->FullPath);
}
};
int main()
{
array<String ^> ^args = Environment::GetCommandLineArgs();
if(args->Length < 2)
{
Console::WriteLine("Usage: Watcher.exe <directory>");
return -1;
}
FileSystemWatcher ^fsWatcher = gcnew FileSystemWatcher( );
fsWatcher->Path = args[1];
fsWatcher->NotifyFilter = static_cast<NotifyFilters>
(NotifyFilters::FileName |
NotifyFilters::Attributes |
NotifyFilters::LastAccess |
NotifyFilters::LastWrite |
NotifyFilters::Security |
NotifyFilters::Size );
FSEventHandler ^handler = gcnew FSEventHandler();
fsWatcher->Changed += gcnew FileSystemEventHandler(
handler, &FSEventHandler::OnChanged);
fsWatcher->Created += gcnew FileSystemEventHandler(
handler, &FSEventHandler::OnChanged);
fsWatcher->Deleted += gcnew FileSystemEventHandler(
handler, &FSEventHandler::OnChanged);
fsWatcher->Renamed += gcnew RenamedEventHandler(
handler, &FSEventHandler::OnRenamed);
fsWatcher->EnableRaisingEvents = true;
Console::WriteLine("Press Enter to quit the sample.");
Console::ReadLine( );
}
目录监视器(Directory Monitor)
使用Boost.Asio扩展
http://www.highscore.de/boost/dir_monitor.zip
SHChangeNotifyRegister
Win SDK Samples 下 ChangeNotifyWatcher 项目,使用SHChangeNotifyRegister
使用SHChangeNotifyRegister、FindFirstChangeNotification、ReadDirectoryChangesW
windows下文件的监控–ReadDirectoryChangesW函数的使用
监控文件和目录的四种方式
以下内容引用理解 ReadDirectoryChangesW
在 Windows Vista 中,SHChangeNotifyRegister 已经可以报告所有文件的所有变更。但问题是,还存在上亿不打算立即升级的 Windows XP 用户。
由于 SHChangeNotifyRegister 基于窗口消息,所以还会带来性能上的问题。如果发生了太多文件变更,应用程序会不断接收到变更消息,你必须自己确认实际发生的事情。对于一部分应用程序来说,这实在是相当的囧。
Windows 2000 引入了两个新接口,FindFirstChangeNotification.aspx) 和 ReadDirectoryChangesW.aspx)。 FindFirstChangeNotification 很容易使用,但没有给出变更文件的信息。即便如此,这个函数对某些应用程序还是很有用的,比如传真服务和 SMTP 服务可以通过拖拽一个文件到一个目录来接受任务队列。ReadDirectoryChangesW 会给出变更的内容和方式, 不过相对的,在使用上也更复杂一些。
同 SHChangeNotifyRegister 一样,这两个新函数也会有性能问题。与 Shell 通知相比,它们的运行速度有明显提升,但在不同目录间移动上千个文件仍然会导致你丢失一部分(或者很多)通知。丢失通知的原因很复杂。令人惊讶的是,似乎与你处理通知的速度有关。
注意,FindFirstChangeNotification 和 ReadDirectoryChangesW 是互斥的,不能同时使用。
Windows XP 引入了最终解决方案,变更日志(Change Journal.aspx))可以跟踪每一个变更的细节,即使你的软件没有运行。很帅的技术,但也相当难用。
第四个,同时也是最后一个解决方案需要安装文件系统过滤驱动,Sysinternals 的 FileMon 就使用了这种技术。在 Windows 驱动开发包(WDK)中有一个例子。这个方案本质上是一个设备驱动,如果没有正确的实现,有可能导致系统稳定性方面的问题。
对我来说,使用 ReadDirectoryChangesW,在性能和复杂度上会是一个很好的平衡。
使用 ReadDirectoryChangesW 的最大挑战在于,在IO模式,处理信号,等待方式,以及线程模型这几个问题的整合上,存在数百种可能性。如果你不是 Win32 I/O 方面的专家,即使最简单的场景,你也很难搞定。
A. I/O模式:
阻塞同步(Blocking synchronous)
触发式同步(Signaled synchronous)
重叠异步(Overlapped asynchronous)
完成例程(Completion Routine) (又名 Asynchronous Procedure Call or APC)
B. 当调用 WaitForXxx 函数的时候:
等待目录句柄
等待 OVERLAPPED 结构体里的 Event 对象
什么都不等 (APCs)
C. 处理通知:
阻塞
WaitForSingleObject
WaitForMultipleObjects
WaitForMultipleObjectsEx
MsgWaitForMultipleObjectsEx
IO完成端口(I/O Completion Ports)
D. 线程模型:
每个工作线程调用一次 ReadDirectoryChangesW.
每个工作线程调用多次 ReadDirectoryChangesW.
在主线程上调用多次 ReadDirectoryChangesW.
多个线程进行多个调用. (I/O Completion Ports)
最后,当调用 ReadDirectoryChangesW 的时候,你可以通过 flags 选择你要监控的内容,包括文件创建,内容变更,属性变更等等。你可以多次调用,每次一个 flag,也可以在一次调用中使用多个 flag。多个 flag 总是正确的解决方案。但如果你为了调试方便,需要一个 flag 一个 flag 的调用的话,那就需要从 ReadDirectoryChangesW 返回的通知缓冲区中读取更多的数据。
QFileSystemWatcher
Qt的QFileSystemWatcher也可监控目录