目录监测
2006-07-20 11:39:18 来源:WEB开发网本文示例源代码或素材下载
C# 中有类 FileSystemWatcher 不但能够知道指定目录树中的文件/目录的改变,而且能够知道是哪个文件/目录在改变,而我用FindFirstChangeNotification等Win API 却不能实现第二个功能,虚耗了不少时间,昨日在msdn中发现 ReadDirectoryChangesW 是可行的,特封装一下,请大家斧正。// 名称: FileSystemWatcher
以下是测试代码
// 功能: 监测指定目录中的文件/目录的改变
// 环境要求: Requires Windows NT 3.51 SP3 or later, and Unsupported Windows 95/98.
// 版权申明: 可任意拷贝、修改、发布
// 作者: 周星星
// 日期: 2003-08-07
// 说明: 未做测试
// VCKBASE.COM
#define _WIN32_WINNT 0x0500
#include <windows.h>
#include <string>
#include <cassert>
enum ACTION { ADDED=1, REMOVED=2, MODIFIED=3, RENAMED=4 };
class FileSystemWatcher
{
public:
typedef void (__stdcall *LPDEALFUNCTION)( ACTION act, std::string filename1, std::string filename2 );
bool Run( std::string path, LPDEALFUNCTION dealfun )
{
WatchedDir = path;
DealFun = dealfun;
DWORD ThreadId;
hThread=CreateThread( NULL,0,Routine,this,0,&ThreadId );
return NULL!=hThread;
}
void Close()
{
if( NULL != hThread )
{
TerminateThread( hThread, 0 );
hThread = NULL;
}
if( INVALID_HANDLE_VALUE != hDir )
{
CloseHandle( hDir );
hDir = INVALID_HANDLE_VALUE;
}
}
FileSystemWatcher() : DealFun(NULL), hThread(NULL), hDir(INVALID_HANDLE_VALUE)
{
}
~FileSystemWatcher()
{
Close();
}
private:
std::string WatchedDir;
LPDEALFUNCTION DealFun;
HANDLE hThread;
HANDLE hDir;
private:
FileSystemWatcher( const FileSystemWatcher& );
FileSystemWatcher operator=( const FileSystemWatcher );
private:
static DWORD WINAPI Routine( LPVOID lParam )
{
FileSystemWatcher* obj = (FileSystemWatcher*)lParam;
obj->hDir = CreateFile(
obj->WatchedDir.c_str(),
GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
NULL
);
if( INVALID_HANDLE_VALUE == obj->hDir ) return false;
char buf[ 2*(sizeof(FILE_NOTIFY_INFORMATION)+MAX_PATH) ];
FILE_NOTIFY_INFORMATION* pNotify=(FILE_NOTIFY_INFORMATION *)buf;
DWORD BytesReturned;
while(true)
{
if( ReadDirectoryChangesW( obj->hDir,
pNotify,
sizeof(buf),
true,
FILE_NOTIFY_CHANGE_FILE_NAME|
FILE_NOTIFY_CHANGE_DIR_NAME|
FILE_NOTIFY_CHANGE_ATTRIBUTES|
FILE_NOTIFY_CHANGE_SIZE|
FILE_NOTIFY_CHANGE_LAST_WRITE|
FILE_NOTIFY_CHANGE_LAST_ACCESS|
FILE_NOTIFY_CHANGE_CREATION|
FILE_NOTIFY_CHANGE_SECURITY,
&BytesReturned,
NULL,
NULL ) )
{
char tmp[MAX_PATH], str1[MAX_PATH], str2[MAX_PATH];
memset( tmp, 0, sizeof(tmp) );
WideCharToMultiByte( CP_ACP,0,pNotify->FileName,pNotify->FileNameLength/2,tmp,99,NULL,NULL );
strcpy( str1, tmp );
if( 0 != pNotify->NextEntryOffset )
{
PFILE_NOTIFY_INFORMATION p = (PFILE_NOTIFY_INFORMATION)((char*)pNotify+pNotify->NextEntryOffset);
memset( tmp, 0, sizeof(tmp) );
WideCharToMultiByte( CP_ACP,0,p->FileName,p->FileNameLength/2,tmp,99,NULL,NULL );
strcpy( str2, tmp );
}
obj->DealFun( (ACTION)pNotify->Action, str1, str2 );
}
else
{
break;
}
}
return 0;
}
};#include <conio.h>
#include <iostream>
using namespace std;
void __stdcall MyDeal( ACTION act, std::string filename1, std::string filename2 )
{
switch( act )
{
case ADDED:
cout << "Added - " << filename1 << endl;
break;
case REMOVED:
cout << "Removed - " << filename1 << endl;
break;
case MODIFIED:
cout << "Modified - " << filename1 << endl;
break;
case RENAMED:
cout << "Rename - " << filename1 << " " << filename2 << endl;
break;
}
}
void main()
{
FileSystemWatcher a;
a.Run( "D:\\", MyDeal );
cout << "Watch D:\\" << endl;
cout << "Press <q> to quit." << endl;
while(getch()!='q');
a.Close();
}
以上代码在 Win2K + VC++6.0 中调试通过,写在同一个文件中是为了调试方便,正式使用时最好能拆分成h文件和cpp文件; 我本想既支持Ansi编码又支持Unicode,但后来心情浮躁,就懒得写了,甚至也没有做足够的测试,所以这段代码写得是很差的,但我实在不想再写了,只想睡觉,所以贴出来抛砖引玉,希望诸位能将修正后的代码贴上来。
更多精彩
赞助商链接