程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> 目錄監測

目錄監測

編輯:關於VC++

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,但後來心情浮躁,就懶得寫了,甚至也沒有做足夠的測試,所以這段代碼寫得是很差的,但我實在不想再寫了,只想睡覺,所以貼出來拋磚引玉,希望諸位能將修正後的代碼貼上來。

本文配套源碼

  1. 上一頁:
  2. 下一頁:
欄目導航
Copyright © 程式師世界 All Rights Reserved