i007.cc

i007.cc

优先队列-降维打击

C++监测文件夹变化

C++监测文件夹变化

转载 2016年11月30日 11:05:44

转自:http://blog.csdn.net/zhihu008/article/details/7995829

Barry注:只是学习ReadDirectoryChangesW的时候发现的一个例子,用于理解ReadDirectoryChangesW的用法,目前发现的不足之处有:

1. ReadDirectoryChangesW的退出不优雅,直接TerminateThread实属下下策,如果close时无限等待,很容易死锁

2. 监控目录不为空时,直接删除见空目录,ReadDirectoryChangesW也不会感知到,线程不会退出,除非手动再次start(会死锁,因为start中的close是无限等待)

FileSystemWatcher.h

[cpp] view plain copy

  1. #ifndef __FILESYSTEMWATCHER_HPP__
  2. #define __FILESYSTEMWATCHER_HPP__
  3. #if(_WIN32_WINNT < 0x0400)
  4. #define _WIN32_WINNT 0x0400
  5. #endif
  6. #include <windows.h>
  7. class FileSystemWatcher
  8. {
  9. public:
  10.  enum Filter
  11.  {
  12.   FILTER_FILE_NAME        = 0x00000001, // add/remove/rename
  13.   FILTER_DIR_NAME         = 0x00000002, // add/remove/rename
  14.   FILTER_ATTR_NAME        = 0x00000004,
  15.   FILTER_SIZE_NAME        = 0x00000008,
  16.   FILTER_LAST_WRITE_NAME  = 0x00000010, // timestamp
  17.   FILTER_LAST_ACCESS_NAME = 0x00000020, // timestamp
  18.   FILTER_CREATION_NAME    = 0x00000040, // timestamp
  19.   FILTER_SECURITY_NAME    = 0x00000100
  20.  };
  21.  enum ACTION
  22.  {
  23.   ACTION_ERRSTOP          = -1,
  24.   ACTION_ADDED            = 0x00000001,
  25.   ACTION_REMOVED          = 0x00000002,
  26.   ACTION_MODIFIED         = 0x00000003,
  27.   ACTION_RENAMED_OLD      = 0x00000004,
  28.   ACTION_RENAMED_NEW      = 0x00000005
  29.  };
  30.  typedef void (__stdcall *LPDEALFUNCTION)( ACTION act, LPCWSTR filename, LPVOID lParam );
  31.  FileSystemWatcher();
  32.  ~FileSystemWatcher();
  33.  // LPCTSTR dir: dont end-with “\\”
  34.  bool Run( LPCTSTR dir, bool bWatchSubtree, DWORD dwNotifyFilter, LPDEALFUNCTION dealfun, LPVOID lParam );
  35.  void Close( DWORD dwMilliseconds=INFINITE );
  36. private// no-impl
  37.  FileSystemWatcher( const FileSystemWatcher& );
  38.  FileSystemWatcher operator=( const FileSystemWatcher );
  39. private:
  40.  HANDLE m_hDir;
  41.  DWORD m_dwNotifyFilter;
  42.  bool m_bWatchSubtree;
  43.  HANDLE m_hThread;
  44.  volatile bool m_bRequestStop;
  45.  LPDEALFUNCTION m_DealFun;
  46.  LPVOID m_DealFunParam;
  47.  static DWORD WINAPI Routine( LPVOID lParam );
  48. };
  49. #endif // __FILESYSTEMWATCHER_HPP__

FileSystemWatcher.cpp

[cpp] view plain copy

  1. #include “FileSystemWatcher.h”
  2. #include <cassert>
  3. FileSystemWatcher::FileSystemWatcher() : m_hDir(INVALID_HANDLE_VALUE), m_hThread(NULL)
  4. {
  5.  assert( FILTER_FILE_NAME        == FILE_NOTIFY_CHANGE_FILE_NAME   );
  6.  assert( FILTER_DIR_NAME         == FILE_NOTIFY_CHANGE_DIR_NAME    );
  7.  assert( FILTER_ATTR_NAME        == FILE_NOTIFY_CHANGE_ATTRIBUTES  );
  8.  assert( FILTER_SIZE_NAME        == FILE_NOTIFY_CHANGE_SIZE        );
  9.  assert( FILTER_LAST_WRITE_NAME  == FILE_NOTIFY_CHANGE_LAST_WRITE  );
  10.  assert( FILTER_LAST_ACCESS_NAME == FILE_NOTIFY_CHANGE_LAST_ACCESS );
  11.  assert( FILTER_CREATION_NAME    == FILE_NOTIFY_CHANGE_CREATION    );
  12.  assert( FILTER_SECURITY_NAME    == FILE_NOTIFY_CHANGE_SECURITY    );
  13.  assert( ACTION_ADDED            == FILE_ACTION_ADDED              );
  14.  assert( ACTION_REMOVED          == FILE_ACTION_REMOVED            );
  15.  assert( ACTION_MODIFIED         == FILE_ACTION_MODIFIED           );
  16.  assert( ACTION_RENAMED_OLD      == FILE_ACTION_RENAMED_OLD_NAME   );
  17.  assert( ACTION_RENAMED_NEW      == FILE_ACTION_RENAMED_NEW_NAME   );
  18. }
  19. FileSystemWatcher::~FileSystemWatcher()
  20. {
  21.  Close();
  22. }
  23. bool FileSystemWatcher::Run( LPCTSTR dir, bool bWatchSubtree, DWORD dwNotifyFilter, LPDEALFUNCTION dealfun, LPVOID lParam )
  24. {
  25.  Close();
  26.  m_hDir = CreateFile(//dir目录不能以’\’结尾,否则监测不到dir目录被删除,不以\结尾,可以检测到(仅限于空目录时)
  27.   dir,
  28.   GENERIC_READ,
  29.   FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
  30.   NULL,
  31.   OPEN_EXISTING,
  32.   FILE_FLAG_BACKUP_SEMANTICS,
  33.   NULL
  34.   );
  35.  if( INVALID_HANDLE_VALUE == m_hDir ) return false;
  36.  m_bWatchSubtree = bWatchSubtree;
  37.  m_dwNotifyFilter = dwNotifyFilter;
  38.  m_DealFun = dealfun;
  39.  m_DealFunParam = lParam;
  40.  m_bRequestStop = false;
  41.  DWORD ThreadId;
  42.  m_hThread = CreateThread( NULL,0,Routine,this,0,&ThreadId );
  43.  if( NULL == m_hThread )
  44.  {
  45.   CloseHandle( m_hDir );
  46.   m_hDir = INVALID_HANDLE_VALUE;
  47.  }
  48.  return NULL!=m_hThread;
  49. }
  50. void FileSystemWatcher::Close( DWORD dwMilliseconds )
  51. {
  52.  if( NULL != m_hThread )
  53.  {
  54.   m_bRequestStop = true;
  55.   if( WAIT_TIMEOUT == WaitForSingleObject(m_hThread,dwMilliseconds) )
  56.    TerminateThread( m_hThread, 0 );
  57.   CloseHandle( m_hThread );
  58.   m_hThread = NULL;
  59.  }
  60.  if( INVALID_HANDLE_VALUE != m_hDir )
  61.  {
  62.   CloseHandle( m_hDir );
  63.   m_hDir = INVALID_HANDLE_VALUE;
  64.  }
  65. }
  66. DWORD WINAPI FileSystemWatcher::Routine( LPVOID lParam )
  67. {
  68.  FileSystemWatcher& obj = *(FileSystemWatcher*)lParam;
  69.  BYTE buf[ 2*(sizeof(FILE_NOTIFY_INFORMATION)+2*MAX_PATH)+2 ];
  70.  FILE_NOTIFY_INFORMATION* pNotify=(FILE_NOTIFY_INFORMATION *)buf;
  71.  DWORD BytesReturned;
  72.  while( !obj.m_bRequestStop )
  73.  {
  74.   if( ReadDirectoryChangesW( obj.m_hDir,
  75.    pNotify,
  76.    sizeof(buf)-2,
  77.    obj.m_bWatchSubtree,
  78.    obj.m_dwNotifyFilter,
  79.    &BytesReturned,
  80.    NULL,
  81.    NULL ) ) // 无限等待,应当使用异步方式
  82.   {
  83.    for( FILE_NOTIFY_INFORMATION* p=pNotify; p; )
  84.    {
  85.     WCHAR c = p->FileName[p->FileNameLength/2];
  86.     p->FileName[p->FileNameLength/2] = L‘\0’;
  87.     obj.m_DealFun( (ACTION)p->Action, p->FileName, obj.m_DealFunParam );
  88.     p->FileName[p->FileNameLength/2] = c;
  89.     if( p->NextEntryOffset )
  90.      p  = (PFILE_NOTIFY_INFORMATION)( (BYTE*)p + p->NextEntryOffset );
  91.     else
  92.      p = 0;
  93.    }
  94.   }
  95.   else
  96.   {
  97.    obj.m_DealFun( (ACTION)ACTION_ERRSTOP, 0, obj.m_DealFunParam );
  98.    break;
  99.   }
  100.  }
  101.  return 0;
  102. }

main函数

[cpp] view plain copy

  1. #include “stdafx.h”
  2. #include “FileSystemWatcher.h”
  3. #include <stdio.h>
  4. #include <locale.h>
  5. #include <assert.h>
  6. #include <tchar.h>
  7. #include <conio.h>
  8. void __stdcall MyDeal( FileSystemWatcher::ACTION act, LPCWSTR filename, LPVOID lParam )
  9. {
  10.  static FileSystemWatcher::ACTION pre = FileSystemWatcher::ACTION_ERRSTOP;
  11.  switch( act )
  12.  {
  13.  case FileSystemWatcher::ACTION_ADDED:
  14.   wprintf_s( L“Added     – %s\n”, filename );
  15.   break;
  16.  case FileSystemWatcher::ACTION_REMOVED:
  17.   wprintf_s( L“Removed   – %s\n”, filename );
  18.   break;
  19.  case FileSystemWatcher::ACTION_MODIFIED:
  20.   wprintf_s( L“Modified  – %s\n”, filename );
  21.   break;
  22.  case FileSystemWatcher::ACTION_RENAMED_OLD:
  23.   wprintf_s( L“Rename(O) – %s\n”, filename );
  24.   break;
  25.  case FileSystemWatcher::ACTION_RENAMED_NEW:
  26.   assert( pre == FileSystemWatcher::ACTION_RENAMED_OLD );
  27.   wprintf_s( L“Rename(N) – %s\n”, filename );
  28.   break;
  29.  case FileSystemWatcher::ACTION_ERRSTOP:
  30.  default:
  31.   wprintf_s( L“—ERROR—%s\n”, filename );
  32.   break;
  33.  }
  34.  pre = act;
  35. }
  36. int main()
  37. {
  38.  LPCTSTR sDir= TEXT(“D:\\监测文件夹”);
  39.  DWORD dwNotifyFilter = FileSystemWatcher::FILTER_FILE_NAME|FileSystemWatcher::FILTER_DIR_NAME;
  40.  FileSystemWatcher fsw;
  41.  bool r = fsw.Run( sDir, true, dwNotifyFilter, &MyDeal, 0 );
  42.  if( !r ) return -1;
  43.  _tsetlocale( LC_CTYPE, TEXT(“chs”) );
  44.  _tprintf_s( TEXT(“Watch%s\n”), sDir );
  45.  _tprintf_s( TEXT(“Press <q> to quit.\n”) );
  46.  while( _getch() != ‘q’ );
  47.  fsw.Close(1000);
  48.  return 0;
  49. }

One thought on “C++监测文件夹变化

  • willPost author

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

发表回复