国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > C++ > 正文

VC++文件監控之ReadDirectoryChangesW

2020-01-26 13:29:25
字體:
來源:轉載
供稿:網友

我這里只介紹采用ReadDirectoryChangesW對文件目錄實施監控

關鍵代碼

CfgdsgDlg * dlg = (CfgdsgDlg*)lparam;   HANDLE hDir;   char notify[1024];   DWORD cbBytes,i;   char AnsiChar[3];   wchar_t UnicodeChar[2];   CString path;   FILE_NOTIFY_INFORMATION *pnotify=(FILE_NOTIFY_INFORMATION *)notify;   FILE_NOTIFY_INFORMATION *tmp;    GetCurrentDirectory(MAX_PATH,path.GetBuffer(MAX_PATH+1));  hDir = CreateFile( path, FILE_LIST_DIRECTORY,    FILE_SHARE_READ |     FILE_SHARE_WRITE |     FILE_SHARE_DELETE, NULL,     OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS |     FILE_FLAG_OVERLAPPED, NULL);   if (hDir == INVALID_HANDLE_VALUE)   {      dlg->m_edit.ReplaceSel("hDir:INVALID_HANDLE_VALUE/r/n");    return 0;  }    while (TRUE)   {     if(ReadDirectoryChangesW(hDir, ¬ify, sizeof(notify),      FALSE, FILE_NOTIFY_CHANGE_FILE_NAME| FILE_NOTIFY_CHANGE_LAST_WRITE,       &cbBytes, NULL, NULL))     {        tmp = pnotify;        switch(tmp->Action)       {       case FILE_ACTION_ADDED:          dlg->m_edit.ReplaceSel("Directory/File added (添加文件)- /r/n");        break;       case FILE_ACTION_REMOVED:        dlg->m_edit.ReplaceSel("Directory/File removed (刪除文件)- /r/n");        break;       case FILE_ACTION_MODIFIED:         dlg->m_edit.ReplaceSel("Directory/File modified (修改文件內容)- /r/n");        break;       case FILE_ACTION_RENAMED_OLD_NAME:         dlg->m_edit.ReplaceSel("Directory/File old name (修改文件名字)- /r/n");        break;       case FILE_ACTION_RENAMED_NEW_NAME:         dlg->m_edit.ReplaceSel("Directory/File new name - /r/n");        break;       default:         break;       }    }  }

FILE_NOTIFY_INFORMATION //可以確定是那個文件進行的修改

typedef struct _FILE_NOTIFY_INFORMATION {
DWORD NextEntryOffset;
DWORD Action;//動作
DWORD FileNameLength;//文件名字的長度
WCHAR FileName[1];//文件名字
} FILE_NOTIFY_INFORMATION,
*PFILE_NOTIFY_INFORMATION;

ReadDirectoryChangesW 返回類型(見MSDN)

Value Meaning

FILE_ACTION_ADDED
0x00000001

The file was added to the directory.

FILE_ACTION_REMOVED
0x00000002

The file was removed from the directory.

FILE_ACTION_MODIFIED
0x00000003

The file was modified. This can be a change in the time stamp or attributes.

FILE_ACTION_RENAMED_OLD_NAME
0x00000004

The file was renamed and this is the old name.

FILE_ACTION_RENAMED_NEW_NAME
0x00000005

The file was renamed and this is the new name.

效果如下:

不足的地方:

只能檢測到指定目錄和下一級目錄,超過目錄級數,該函數檢測不到。

ReadDirectoryChangesW 監控文件夾 (一個簡單的監控示例程序)

.h文件

// .h文件#pragma once typedef void (*PFN_NotifyAction)(DWORD dwAction, LPWSTR szFile, DWORD dwLength); class CDirectoryWatch{public:	CDirectoryWatch(void);	virtual ~CDirectoryWatch(void); public:	BOOL StartDirectoryWatch(LPCTSTR lpszDirectory, PFN_NotifyAction pFn_NotifyAction);	BOOL StopDirectoryWatch(void); private:	static UINT __cdecl ThreadProc(LPVOID lParam);	static UINT __cdecl DirectoryWatch(LPVOID lParam); private:	HANDLE m_hFile;	CWinThread* m_pThread;	TCHAR m_szDirectory[MAX_PATH];};

.cpp文件

// .cpp文件#include "StdAfx.h"#include "DirectoryWatch.h"#include <strsafe.h> typedef enum{	MSG_STARTWATCH = (WM_USER + 0x11),	MSG_STOPWATCH,	MSG_EXITTHREAD}; #define MAX_BUFFER_SIZE	(1024) typedef struct _tagWATCHPARAMETERS{	_tagWATCHPARAMETERS()	{		hFile = INVALID_HANDLE_VALUE;		hEvent = NULL;		memset(&ol, 0, sizeof(OVERLAPPED));		pBuffer = NULL;		dwBufferSize = 0;		bExit = FALSE;		pFn_NotifyAction = NULL;	}	HANDLE hFile;	HANDLE hEvent;	OVERLAPPED ol;	BYTE* pBuffer;	DWORD dwBufferSize;	BOOL bExit;	PFN_NotifyAction pFn_NotifyAction;}WATCH_PARAMETERS, *PWATCH_PARAMETERS; CDirectoryWatch::CDirectoryWatch() : m_hFile(INVALID_HANDLE_VALUE), m_pThread(NULL){	memset(m_szDirectory, 0, sizeof(m_szDirectory)); 	m_pThread = AfxBeginThread(ThreadProc, NULL, 0, CREATE_SUSPENDED, 0, NULL);	if(NULL == m_pThread)	{		TRACE("Error Code : %d/n", GetLastError());		return ;	}	m_pThread->m_bAutoDelete = FALSE;	m_pThread->ResumeThread();}  CDirectoryWatch::~CDirectoryWatch(){	if(INVALID_HANDLE_VALUE != m_hFile)	{		CloseHandle(m_hFile);		m_hFile = INVALID_HANDLE_VALUE;	} 	if((NULL != m_pThread) && (NULL != m_pThread->m_hThread))	{ 		m_pThread->PostThreadMessage(MSG_EXITTHREAD, 0, 0);		WaitForSingleObject(m_pThread->m_hThread, INFINITE);		delete m_pThread;		m_pThread = NULL;	}} BOOL CDirectoryWatch::StartDirectoryWatch(LPCTSTR lpszDirectory, PFN_NotifyAction pFn_NotifyAction){	if(NULL == m_pThread)	{		return FALSE;	} 	if(NULL == lpszDirectory)	{		return FALSE;	} 	if(NULL == pFn_NotifyAction)	{		return FALSE;	} 	if(!PathFileExists(lpszDirectory))	{		TRACE("Error Code : %d/n", GetLastError());		return FALSE;	} 	if(!PathIsDirectory(lpszDirectory))	{		TRACE("Error Code : %d/n", GetLastError());		return FALSE;	} 	if(0 == _tcslen(m_szDirectory))	{		StringCchPrintf(m_szDirectory, _countof(m_szDirectory), _T("%s"), lpszDirectory);	}	else if(CSTR_EQUAL != CompareStringOrdinal(m_szDirectory, -1, lpszDirectory, -1, TRUE))	{		TRACE("Not Change Directory./n");		return FALSE;	} 	if(INVALID_HANDLE_VALUE == m_hFile)	{		m_hFile = CreateFile(lpszDirectory, FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,			NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, NULL);		if(INVALID_HANDLE_VALUE == m_hFile)		{			TRACE("Error Code : %d/n", GetLastError());			return FALSE;		}	} 	return m_pThread->PostThreadMessage(MSG_STARTWATCH, (WPARAM)m_hFile, (LPARAM)pFn_NotifyAction);} BOOL CDirectoryWatch::StopDirectoryWatch(){	if(NULL != m_pThread)	{		return m_pThread->PostThreadMessage(MSG_STOPWATCH, 0, 0);	} 	return FALSE;} UINT __cdecl CDirectoryWatch::DirectoryWatch(LPVOID lParam){	WATCH_PARAMETERS* pParam = (WATCH_PARAMETERS*)lParam;	if(NULL == pParam)	{		return 0;	}	HANDLE& hFile = pParam->hFile;	BYTE* pBuffer = pParam->pBuffer;	DWORD dwBufferSize = pParam->dwBufferSize;	OVERLAPPED& ol = pParam->ol;	HANDLE& hEvent = pParam->hEvent;	BOOL& bExit = pParam->bExit;	PFN_NotifyAction pFn_NotifyAction = pParam->pFn_NotifyAction;	DWORD dwBytesReturn = 0;	DWORD dwRet = WAIT_FAILED;	DWORD dwOffSet = 0;	TCHAR szFile[MAX_PATH] = {0};	while(TRUE)	{		if(WAIT_OBJECT_0 != WaitForSingleObject(hEvent, INFINITE))		{			TRACE("Error Code : %d/n", GetLastError());			break;		} 		if(bExit)		{			break;		}			if(!ReadDirectoryChangesW(hFile, pBuffer, dwBufferSize, 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, &dwBytesReturn, &ol, NULL))		{			TRACE("Error Code : %d/n", GetLastError());			break;		}		if(!GetOverlappedResult(hFile, &ol, &dwBytesReturn, TRUE))		{			TRACE("Error Code : %d/n", GetLastError());			break;		}		FILE_NOTIFY_INFORMATION* pFileNotify = (FILE_NOTIFY_INFORMATION*)pBuffer;				do 		{			if(pFn_NotifyAction && (WAIT_OBJECT_0 == WaitForSingleObject(hEvent, 0)))			{				pFn_NotifyAction(pFileNotify->Action, pFileNotify->FileName, (pFileNotify->FileNameLength) / sizeof(WCHAR));			} 			dwOffSet = pFileNotify->NextEntryOffset;			pFileNotify = (FILE_NOTIFY_INFORMATION*)((BYTE*)pFileNotify + dwOffSet);		} while (dwOffSet);	}	TRACE0("DirectoryWatch Thread Exit ... /n");	return 0;} UINT __cdecl CDirectoryWatch::ThreadProc(LPVOID lParam){	WATCH_PARAMETERS* pParam = new WATCH_PARAMETERS; 	if(NULL == pParam)	{		goto __CLEANUP__;	} 	BYTE* pBuffer = new BYTE[MAX_BUFFER_SIZE];	if(NULL == pBuffer)	{		goto __CLEANUP__;	}	memset(pBuffer, 0, MAX_BUFFER_SIZE);	pParam->pBuffer = pBuffer;	pParam->dwBufferSize = MAX_BUFFER_SIZE;	HANDLE hWatchEvent = CreateEvent(NULL, TRUE, FALSE, NULL);	if(NULL == hWatchEvent)	{		goto __CLEANUP__;	}	pParam->ol.hEvent = hWatchEvent;	CWinThread* pThread = NULL;	HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);	if(NULL == hEvent)	{		goto __CLEANUP__;	}	pParam->hEvent = hEvent;	MSG msg;	while(GetMessage(&msg, NULL, 0, 0))	{		switch(msg.message)		{		case MSG_STARTWATCH:			{				HANDLE hFile = (HANDLE)(msg.wParam);				PFN_NotifyAction pFn_NotifyAction = (PFN_NotifyAction)(msg.lParam);				if((INVALID_HANDLE_VALUE == hFile) && (NULL == pFn_NotifyAction))				{					break;				}				if(NULL == pThread)				{					pParam->hFile = hFile;					pParam->pFn_NotifyAction = pFn_NotifyAction;					pThread = AfxBeginThread(DirectoryWatch, (LPVOID)pParam, 0, CREATE_SUSPENDED, NULL);					if(NULL == pThread)					{						goto __CLEANUP__;					}					pThread->m_bAutoDelete = FALSE;					pThread->ResumeThread();				}								SetEvent(hEvent);			}			break; 		case MSG_STOPWATCH:			{				ResetEvent(hEvent);			}			break; 		case MSG_EXITTHREAD:			{				SetEvent(hEvent);				pParam->bExit = FALSE;								if((NULL != pThread) && (NULL != pThread->m_hThread))				{					WaitForSingleObject(pThread->m_hThread, INFINITE);					delete pThread;					pThread = NULL;				}				goto __CLEANUP__;			}					default:			break;		}		TranslateMessage(&msg);		DispatchMessage(&msg);	} __CLEANUP__:	if(NULL != hWatchEvent)	{		CloseHandle(hWatchEvent);		hWatchEvent = NULL;	}	if(NULL != pBuffer)	{		delete[] pBuffer;		pBuffer = NULL;	}	if(NULL != pParam)	{		delete pParam;		pParam = NULL;	}	TRACE0("ThreadProc Thread Exit .../n");	return 0;}

測試代碼

// 測試代碼 #include "stdafx.h" #include "DirectoryWatch.h" void NotifyAction(DWORD dwAction, LPWSTR szFile, DWORD dwLength){	switch(dwAction)	{	case FILE_ACTION_ADDED:		wprintf(L"FILE_ACTION_ADDED: /n/t");		break; 	case FILE_ACTION_REMOVED:		wprintf(L"FILE_ACTION_REMOVED: /n/t");		break; 	case FILE_ACTION_MODIFIED:		wprintf(L"FILE_ACTION_MODIFIED: /n/t");		break; 	case FILE_ACTION_RENAMED_OLD_NAME:		wprintf(L"FILE_ACTION_RENAMED_OLD_NAME: /n/t");		break; 	case FILE_ACTION_RENAMED_NEW_NAME:		wprintf(L"FILE_ACTION_RENAMED_NEW_NAME: /n/t");		break; 	default:		break;	}	WCHAR szPath[MAX_PATH] = {0};	wmemcpy(szPath, szFile, min(dwLength, MAX_PATH));	wprintf(L"%s/n", szPath);} int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]){	CDirectoryWatch watch;	wprintf(L"Start Directory Watch .../n");	watch.StartDirectoryWatch(_T("F://11"), NotifyAction);	Sleep(30 * 1000);		watch.StopDirectoryWatch();	wprintf(L"Stop Directory Watch .../n"); 	Sleep(10 * 1000); 	wprintf(L"Start Directory Watch .../n");	watch.StartDirectoryWatch(_T("F://11"), NotifyAction);	Sleep(30 * 1000);		watch.StopDirectoryWatch();	wprintf(L"Stop Directory Watch .../n");	Sleep(30 * 1000);	wprintf(L"Process Exit .../n");	return 0;}

效果如下圖所示:

使用ReadDirectoryChangesW API監控文件系統的改變

在C++中若想要監控檔案系統改變有很多方法,可以用FindFirstChangeNotification取得檔案變更、或是Hook底層的API等方法來實現,這邊使用ReadDirectoryChangesW API來實現,該API使用前必須先加入Kernel32.lib。

并加入Windows.h的標頭檔

#include "Windows.h"

這些步驟做完后在程式中就可以看到ReadDirectoryChangesW API了,其函式原型如下:

BOOL WINAPI ReadDirectoryChangesW( __in     HANDLE hDirectory, __out    LPVOID lpBuffer, __in     DWORD nBufferLength, __in     BOOL bWatchSubtree, __in     DWORD dwNotifyFilter, __out_opt  LPDWORD lpBytesReturned, __inout_opt LPOVERLAPPED lpOverlapped, __in_opt   LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);

該API必須帶入八個參數,hDirectory帶入的是要監控的目錄Handle、lpBuffer帶入的是用來回傳變動資料的空間、nBufferLength是lpBuffer空間的大小、bWatchSubtree是指定是否偵測子目錄、dwNotifyFilter是指定監控的目錄有哪些動作時需要通知、lpBytesReturned是用來回傳變動資料內含的長度、lpOverlapped可用來在非同步環境下使用重疊IO用、lpCompletionRoutine則是當監控完成或取消時所呼叫的回調函式。

其中dwNotifyFilter的值可設定的有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,詳細所代表的意義可參閱ReadDirectoryChangesW function

了解了函式原型后,就可以開始進入實際的使用。剛有提到說在ReadDirectoryChangesW API函式必須要帶入的第一個參數是要監控的目錄Handle,所以我們必須透過CreateFile API取得要監控的目錄Handle,像是下面這樣:

HANDLE hDirectoryHandle  = NULL;hDirectoryHandle = ::CreateFileA(  file,            FILE_LIST_DIRECTORY,          FILE_SHARE_READ              | FILE_SHARE_WRITE  | FILE_SHARE_DELETE,  NULL,                  OPEN_EXISTING,             FILE_FLAG_BACKUP_SEMANTICS        | FILE_FLAG_OVERLAPPED,  NULL); if(hDirectoryHandle == INVALID_HANDLE_VALUE)  return;

取得監控的目錄Handle后,將其帶入ReadDirectoryChangesw API,順帶帶入像是回傳變動資料的Buffer空間、與要監控的變動類型等必要參數。像是下面這樣:

int    nBufferSize      = 1024;char*  buffer        = new char[nBufferSize];DWORD dwBytes = 0;memset(buffer, 0, nBufferSize);if(!::ReadDirectoryChangesW(  hDirectoryHandle,              buffer,                  nBufferSize,      bIncludeSubdirectories,         FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_FILE_NAME,     &dwBytes,               NULL,            NULL) || GetLastError() == ERROR_INVALID_HANDLE){  break;}if(!dwBytes){  printf("Buffer overflow~~/r/n");}

這邊需注意到的是,若是變動的資料太多,提供的存儲空間不足以存放時,回傳的變動資料長度會是0,此時所有變動資料都會丟失。這樣的情況多半只會出在一瞬間大量的變動,可以增大存儲空間或是減少監控的變動類型,以減少回傳的資料量,避免溢位的發生。

若是運行沒發生問題,變動的資料會存放在當初塞進去的存儲空間,該空間的資料其實是FILE_NOTIFY_INFORMATION structure的型態存在,因此我們可將存儲空間的資料轉換成PFILE_NOTIFY_INFORMATION。

主站蜘蛛池模板: 郴州市| 仪征市| 家居| 广水市| 微山县| 曲麻莱县| 邵东县| 韶关市| 新兴县| 浮梁县| 宁强县| 河曲县| 吉安县| 临朐县| 互助| 南川市| 夏河县| 花垣县| 天台县| 贵州省| 巴彦淖尔市| 璧山县| 都兰县| 闵行区| 丽水市| 汶上县| 江山市| 延安市| 巍山| 岱山县| 鄂托克前旗| 衢州市| 肃宁县| 和硕县| 那坡县| 霍林郭勒市| 丰都县| 榆林市| 桐梓县| 轮台县| 加查县|