C++监测文件夹变化
C++监测文件夹变化
转自:http://blog.csdn.net/zhihu008/article/details/7995829
Barry注:只是学习ReadDirectoryChangesW的时候发现的一个例子,用于理解ReadDirectoryChangesW的用法,目前发现的不足之处有:
1. ReadDirectoryChangesW的退出不优雅,直接TerminateThread实属下下策,如果close时无限等待,很容易死锁
2. 监控目录不为空时,直接删除见空目录,ReadDirectoryChangesW也不会感知到,线程不会退出,除非手动再次start(会死锁,因为start中的close是无限等待)
FileSystemWatcher.h
- #ifndef __FILESYSTEMWATCHER_HPP__
- #define __FILESYSTEMWATCHER_HPP__
- #if(_WIN32_WINNT < 0x0400)
- #define _WIN32_WINNT 0x0400
- #endif
- #include <windows.h>
- class FileSystemWatcher
- {
- public:
- enum Filter
- {
- FILTER_FILE_NAME = 0x00000001, // add/remove/rename
- FILTER_DIR_NAME = 0x00000002, // add/remove/rename
- FILTER_ATTR_NAME = 0x00000004,
- FILTER_SIZE_NAME = 0x00000008,
- FILTER_LAST_WRITE_NAME = 0x00000010, // timestamp
- FILTER_LAST_ACCESS_NAME = 0x00000020, // timestamp
- FILTER_CREATION_NAME = 0x00000040, // timestamp
- FILTER_SECURITY_NAME = 0x00000100
- };
- enum ACTION
- {
- ACTION_ERRSTOP = -1,
- ACTION_ADDED = 0x00000001,
- ACTION_REMOVED = 0x00000002,
- ACTION_MODIFIED = 0x00000003,
- ACTION_RENAMED_OLD = 0x00000004,
- ACTION_RENAMED_NEW = 0x00000005
- };
- typedef void (__stdcall *LPDEALFUNCTION)( ACTION act, LPCWSTR filename, LPVOID lParam );
- FileSystemWatcher();
- ~FileSystemWatcher();
- // LPCTSTR dir: dont end-with “\\”
- bool Run( LPCTSTR dir, bool bWatchSubtree, DWORD dwNotifyFilter, LPDEALFUNCTION dealfun, LPVOID lParam );
- void Close( DWORD dwMilliseconds=INFINITE );
- private: // no-impl
- FileSystemWatcher( const FileSystemWatcher& );
- FileSystemWatcher operator=( const FileSystemWatcher );
- private:
- HANDLE m_hDir;
- DWORD m_dwNotifyFilter;
- bool m_bWatchSubtree;
- HANDLE m_hThread;
- volatile bool m_bRequestStop;
- LPDEALFUNCTION m_DealFun;
- LPVOID m_DealFunParam;
- static DWORD WINAPI Routine( LPVOID lParam );
- };
- #endif // __FILESYSTEMWATCHER_HPP__
FileSystemWatcher.cpp
- #include “FileSystemWatcher.h”
- #include <cassert>
- FileSystemWatcher::FileSystemWatcher() : m_hDir(INVALID_HANDLE_VALUE), m_hThread(NULL)
- {
- assert( FILTER_FILE_NAME == FILE_NOTIFY_CHANGE_FILE_NAME );
- assert( FILTER_DIR_NAME == FILE_NOTIFY_CHANGE_DIR_NAME );
- assert( FILTER_ATTR_NAME == FILE_NOTIFY_CHANGE_ATTRIBUTES );
- assert( FILTER_SIZE_NAME == FILE_NOTIFY_CHANGE_SIZE );
- assert( FILTER_LAST_WRITE_NAME == FILE_NOTIFY_CHANGE_LAST_WRITE );
- assert( FILTER_LAST_ACCESS_NAME == FILE_NOTIFY_CHANGE_LAST_ACCESS );
- assert( FILTER_CREATION_NAME == FILE_NOTIFY_CHANGE_CREATION );
- assert( FILTER_SECURITY_NAME == FILE_NOTIFY_CHANGE_SECURITY );
- assert( ACTION_ADDED == FILE_ACTION_ADDED );
- assert( ACTION_REMOVED == FILE_ACTION_REMOVED );
- assert( ACTION_MODIFIED == FILE_ACTION_MODIFIED );
- assert( ACTION_RENAMED_OLD == FILE_ACTION_RENAMED_OLD_NAME );
- assert( ACTION_RENAMED_NEW == FILE_ACTION_RENAMED_NEW_NAME );
- }
- FileSystemWatcher::~FileSystemWatcher()
- {
- Close();
- }
- bool FileSystemWatcher::Run( LPCTSTR dir, bool bWatchSubtree, DWORD dwNotifyFilter, LPDEALFUNCTION dealfun, LPVOID lParam )
- {
- Close();
- m_hDir = CreateFile(//dir目录不能以’\’结尾,否则监测不到dir目录被删除,不以\结尾,可以检测到(仅限于空目录时)
- dir,
- GENERIC_READ,
- FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
- NULL,
- OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS,
- NULL
- );
- if( INVALID_HANDLE_VALUE == m_hDir ) return false;
- m_bWatchSubtree = bWatchSubtree;
- m_dwNotifyFilter = dwNotifyFilter;
- m_DealFun = dealfun;
- m_DealFunParam = lParam;
- m_bRequestStop = false;
- DWORD ThreadId;
- m_hThread = CreateThread( NULL,0,Routine,this,0,&ThreadId );
- if( NULL == m_hThread )
- {
- CloseHandle( m_hDir );
- m_hDir = INVALID_HANDLE_VALUE;
- }
- return NULL!=m_hThread;
- }
- void FileSystemWatcher::Close( DWORD dwMilliseconds )
- {
- if( NULL != m_hThread )
- {
- m_bRequestStop = true;
- if( WAIT_TIMEOUT == WaitForSingleObject(m_hThread,dwMilliseconds) )
- TerminateThread( m_hThread, 0 );
- CloseHandle( m_hThread );
- m_hThread = NULL;
- }
- if( INVALID_HANDLE_VALUE != m_hDir )
- {
- CloseHandle( m_hDir );
- m_hDir = INVALID_HANDLE_VALUE;
- }
- }
- DWORD WINAPI FileSystemWatcher::Routine( LPVOID lParam )
- {
- FileSystemWatcher& obj = *(FileSystemWatcher*)lParam;
- BYTE buf[ 2*(sizeof(FILE_NOTIFY_INFORMATION)+2*MAX_PATH)+2 ];
- FILE_NOTIFY_INFORMATION* pNotify=(FILE_NOTIFY_INFORMATION *)buf;
- DWORD BytesReturned;
- while( !obj.m_bRequestStop )
- {
- if( ReadDirectoryChangesW( obj.m_hDir,
- pNotify,
- sizeof(buf)-2,
- obj.m_bWatchSubtree,
- obj.m_dwNotifyFilter,
- &BytesReturned,
- NULL,
- NULL ) ) // 无限等待,应当使用异步方式
- {
- for( FILE_NOTIFY_INFORMATION* p=pNotify; p; )
- {
- WCHAR c = p->FileName[p->FileNameLength/2];
- p->FileName[p->FileNameLength/2] = L‘\0’;
- obj.m_DealFun( (ACTION)p->Action, p->FileName, obj.m_DealFunParam );
- p->FileName[p->FileNameLength/2] = c;
- if( p->NextEntryOffset )
- p = (PFILE_NOTIFY_INFORMATION)( (BYTE*)p + p->NextEntryOffset );
- else
- p = 0;
- }
- }
- else
- {
- obj.m_DealFun( (ACTION)ACTION_ERRSTOP, 0, obj.m_DealFunParam );
- break;
- }
- }
- return 0;
- }
main函数
- #include “stdafx.h”
- #include “FileSystemWatcher.h”
- #include <stdio.h>
- #include <locale.h>
- #include <assert.h>
- #include <tchar.h>
- #include <conio.h>
- void __stdcall MyDeal( FileSystemWatcher::ACTION act, LPCWSTR filename, LPVOID lParam )
- {
- static FileSystemWatcher::ACTION pre = FileSystemWatcher::ACTION_ERRSTOP;
- switch( act )
- {
- case FileSystemWatcher::ACTION_ADDED:
- wprintf_s( L“Added – %s\n”, filename );
- break;
- case FileSystemWatcher::ACTION_REMOVED:
- wprintf_s( L“Removed – %s\n”, filename );
- break;
- case FileSystemWatcher::ACTION_MODIFIED:
- wprintf_s( L“Modified – %s\n”, filename );
- break;
- case FileSystemWatcher::ACTION_RENAMED_OLD:
- wprintf_s( L“Rename(O) – %s\n”, filename );
- break;
- case FileSystemWatcher::ACTION_RENAMED_NEW:
- assert( pre == FileSystemWatcher::ACTION_RENAMED_OLD );
- wprintf_s( L“Rename(N) – %s\n”, filename );
- break;
- case FileSystemWatcher::ACTION_ERRSTOP:
- default:
- wprintf_s( L“—ERROR—%s\n”, filename );
- break;
- }
- pre = act;
- }
- int main()
- {
- LPCTSTR sDir= TEXT(“D:\\监测文件夹”);
- DWORD dwNotifyFilter = FileSystemWatcher::FILTER_FILE_NAME|FileSystemWatcher::FILTER_DIR_NAME;
- FileSystemWatcher fsw;
- bool r = fsw.Run( sDir, true, dwNotifyFilter, &MyDeal, 0 );
- if( !r ) return -1;
- _tsetlocale( LC_CTYPE, TEXT(“chs”) );
- _tprintf_s( TEXT(“Watch%s\n”), sDir );
- _tprintf_s( TEXT(“Press <q> to quit.\n”) );
- while( _getch() != ‘q’ );
- fsw.Close(1000);
- return 0;
- }

可以实现配置文件更新自动reload,不用再手动敲reload指令了,reload指令太难记了