Задача: Отслеживание изменений файла
Исходник: отслеживание изменений файла на основе FindFirstChangeNotification, язык: C++ [code #585, hits: 14093]
автор: - [добавлен: 09.02.2009]
  1. /// \file file_change_notify.h
  2. /// Copyright (C) 2009 Grisha Spivak - rusted dreams, distributed under the MIT License
  3.  
  4. #ifndef file_change_notify_h
  5. #define file_change_notify_h
  6.  
  7. #include <boost/noncopyable.hpp>
  8. #include <boost/filesystem.hpp>
  9. #include <boost/thread.hpp>
  10.  
  11. #include <windows.h>
  12.  
  13. namespace wnd_system
  14. {
  15. // watches for file modification and posts specified windows message to specified window
  16. class file_change_notifier : boost::noncopyable
  17. {
  18. public:
  19. file_change_notifier( boost::filesystem::path const & filepath, HWND hwnd, unsigned message_code );
  20. ~file_change_notifier();
  21.  
  22. private:
  23. HANDLE dir_changed_, wait_end_;
  24. boost::thread waiter_;
  25. };
  26. }
  27.  
  28. #endif //file_change_notify_h
  29.  
  30.  
  31. /// \file file_change_notify.cpp
  32. /// Copyright (C) 2009 Grisha Spivak - rusted dreams, distributed under the MIT License
  33.  
  34. #include <stdexcept>
  35.  
  36. #include "file_change_notify.h"
  37.  
  38. namespace
  39. {
  40. struct wait_thread
  41. {
  42. HANDLE dir_changed_;
  43. HANDLE wait_end_;
  44. boost::filesystem::path filepath_;
  45. std::time_t last_write_;
  46. HWND hwnd_;
  47. unsigned message_code_;
  48.  
  49. void operator()()
  50. {
  51. HANDLE handles[] = { dir_changed_, wait_end_ };
  52. for( ; ; )
  53. {
  54. switch( WaitForMultipleObjects( 2, handles, false, INFINITE ) )
  55. {
  56. case WAIT_OBJECT_0:
  57. {
  58. Sleep( 50 ); // need to sleep a little to prevent getting old last_write_time
  59. try
  60. {
  61. std::time_t last_write = boost::filesystem::last_write_time( filepath_ );
  62. if( last_write != last_write_ )
  63. {
  64. PostMessageA( hwnd_, message_code_, 0, 0 );
  65. last_write_ = last_write;
  66. }
  67. }
  68. catch( ... )
  69. {
  70. }
  71.  
  72. FindNextChangeNotification( dir_changed_ );
  73. }
  74. break;
  75. case WAIT_OBJECT_0 + 1:
  76. return;
  77. }
  78. }
  79. }
  80. };
  81.  
  82. HANDLE create_dir_change_notification( boost::filesystem::path const & filepath )
  83. {
  84. HANDLE h = FindFirstChangeNotificationA(
  85. filepath.parent_path().string().c_str(), false, FILE_NOTIFY_CHANGE_LAST_WRITE );
  86. if( h == INVALID_HANDLE_VALUE )
  87. throw std::runtime_error( "FindFirstChangeNotificationA failed" );
  88. return h;
  89. }
  90. }
  91.  
  92. wnd_system::file_change_notifier::file_change_notifier(
  93. boost::filesystem::path const & filepath, HWND hwnd, unsigned message_code )
  94. : dir_changed_( create_dir_change_notification( filepath ) ),
  95. wait_end_( CreateEventA( 0, false, false, 0 ) )
  96. {
  97. if( wait_end_ == INVALID_HANDLE_VALUE )
  98. {
  99. FindCloseChangeNotification( dir_changed_ );
  100. throw std::runtime_error( "CreateEventA failed" );
  101. }
  102.  
  103. try
  104. {
  105. wait_thread waiter =
  106. {
  107. dir_changed_,
  108. wait_end_,
  109. filepath,
  110. boost::filesystem::last_write_time( filepath ),
  111. hwnd,
  112. message_code
  113. };
  114.  
  115. waiter_ = boost::thread( waiter );
  116. }
  117. catch( ... )
  118. {
  119. CloseHandle( wait_end_ );
  120. FindCloseChangeNotification( dir_changed_ );
  121. throw;
  122. }
  123. }
  124.  
  125. wnd_system::file_change_notifier::~file_change_notifier()
  126. {
  127. SetEvent( wait_end_ );
  128. waiter_.join();
  129. CloseHandle( wait_end_ );
  130. FindCloseChangeNotification( dir_changed_ );
  131. }
как пользоваться — создаем экземпляр класса когда хотим начать следить за изменениями какого-то файла, когда перестаем следить — уничтожаем. при записи в этот файл указанному в конструкторе окну посылается указанное в конструкторе же сообщение.
при необходимости можно легко модифицировать под для wchar_t.

ps. удаление файла в данном случае изменением не ситается — об этом оповещения не приходит, мне так было нужно — если кому-то надо другое поведение, то может поменять сам — в качестве упражнения.

(c)rsdn.ru/forum/message/3282352.all.aspx

+добавить реализацию