ReadDirectoryChanges實現監控文件夾

#include <tchar.h>
#include <stdio.h>
#include <Windows.h>
#include <assert.h>
#include <locale>

#pragma warning(disable: 4995)
#pragma warning(disable: 4996)
#include "adkprecomp.h"
#include "adkfile.h"

int parse_notify_information(const wchar_t *src_dir, const wchar_t *dst_dir, const PFILE_NOTIFY_INFORMATION ctx)
{
	PFILE_NOTIFY_INFORMATION fcinfo = ctx;

	wchar_t file_name[MAX_PATH] = {0};
	wchar_t src_file[MAX_PATH] = {0};
	wchar_t dst_file[MAX_PATH] = {0};

	if (!fcinfo) return -1;

	do 
	{
		memset(file_name, L'\0', sizeof(file_name));
		memcpy_s(file_name, sizeof(file_name), fcinfo->FileName, fcinfo->FileNameLength);

		swprintf_s(src_file, _countof(src_file), L"%ws%ws", src_dir, file_name);
		swprintf_s(dst_file, _countof(dst_file), L"%ws%ws", dst_dir, file_name);
		AdkCreateDirectoryW(dst_file);

		switch (fcinfo->Action)
		{
		case FILE_ACTION_ADDED:
			wprintf_s(L"add file %ws \r\n", file_name);
			break;
		case FILE_ACTION_MODIFIED:
			wprintf_s(L"modified file %ws \r\n", file_name);

			// 此處可能可能出現拷貝失敗錯誤碼爲32的錯誤
			// 解決辦法:使用while循環重試CopyFileW
			//
			while(!CopyFileW(src_file, dst_file, FALSE))
			{
				Sleep(10);
			}

			break;
		case FILE_ACTION_REMOVED:
			wprintf_s(L"removed file %ws \r\n", file_name);
			break;
		case FILE_ACTION_RENAMED_NEW_NAME:
			wprintf_s(L"renamed new file %ws \r\n", file_name);
			break;
		case FILE_ACTION_RENAMED_OLD_NAME:
			wprintf_s(L"renamed old file %ws \r\n", file_name);
			break;
		default:
			//assert(!L"unknown action type!!!");
			break;
		}

		fcinfo = (PFILE_NOTIFY_INFORMATION)((unsigned long)fcinfo + fcinfo->NextEntryOffset);

	} while (fcinfo->NextEntryOffset);

	return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
	HANDLE change_handle = INVALID_HANDLE_VALUE;

	PFILE_NOTIFY_INFORMATION fcinfo = NULL;

	OVERLAPPED overlapped = {0};

	wchar_t apppath[MAX_PATH] = {0};
	wchar_t config_file[MAX_PATH] = {0};
	wchar_t src_dir[MAX_PATH] = {0};
	wchar_t dst_dir[MAX_PATH] = {0};

	char buf[2048] = {0};			// 這裏的大小需要足夠大,可改成動態申請較大的內存空間

	unsigned long wait_ret = 0;
	unsigned long return_size = 0;
	unsigned long error_code = 0;

	setlocale(LC_ALL, "chs");

	GetModuleFileNameW(NULL, apppath, _countof(apppath));
	apppath[wcslen(apppath) - wcslen(wcsrchr(apppath, L'\\')) + 1] = L'\0';
	
	swprintf_s(config_file, _countof(config_file), L"%ws%ws", apppath, L"fmonitor.ini");

	GetPrivateProfileStringW(L"dir", L"src", NULL, src_dir, _countof(src_dir), config_file);
	GetPrivateProfileStringW(L"dir", L"dst", NULL, dst_dir, _countof(dst_dir), config_file);
	if (src_dir[wcslen(src_dir) - 1] != L'\\')
	{
		wcscat_s(src_dir, _countof(src_dir), L"\\");
	}
	if (dst_dir[wcslen(dst_dir) - 1] != L'\\')
	{
		wcscat_s(dst_dir, _countof(dst_dir), L"\\");
	}
	AdkCreateDirectoryW(dst_dir);

	wprintf_s(L"src_dir = %ws \r\ndst_dir = %ws \r\n", src_dir, dst_dir);

	do 
	{
		overlapped.hEvent = CreateEventW(NULL, TRUE, FALSE, L"stop_monitor_event_name");
		assert(overlapped.hEvent);

		change_handle = CreateFileW(
			src_dir, 
			FILE_LIST_DIRECTORY, 
			FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, 
			NULL, 
			OPEN_EXISTING, 
			FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, 
			NULL
			);
		if (change_handle == INVALID_HANDLE_VALUE)
		{
			assert(0);
			break;
		}

		while(1)
		{
			wprintf_s(L"waitting change ... \r\n");

			memset(buf, '\0', sizeof(buf));

			if (!ReadDirectoryChangesW(
				change_handle, 
				buf, 
				sizeof(buf), 
				TRUE, 
				FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_SIZE,	// 監控文件大小的變化 
				&return_size, 
				&overlapped, 
				NULL
				))
			{
				error_code = GetLastError();
				Sleep(10);
				continue;
			}

			if (!GetOverlappedResult(change_handle, &overlapped, &return_size, TRUE))
			{
				error_code = GetLastError();
				Sleep(10);
				continue;
			}
			if(overlapped.Internal != 0)
			{
				wprintf_s(L"stoped monitor!! \r\n");
				break;
			}
			if(return_size == 0)	// buf緩存太小將導致retrun_size == 0, 詳細見MSDN說明
			{
				continue;
			}

			parse_notify_information(src_dir, dst_dir, (PFILE_NOTIFY_INFORMATION)buf);
		}

	} while (0);

	CloseHandle(overlapped.hEvent);
	CloseHandle(change_handle);
	change_handle = INVALID_HANDLE_VALUE;

	return 0;
}

實現監控文件夾中的文件變化,並將文件拷貝出來

有些API如AdkMalloc等,爲自主實現的庫,需要AdkPrecomp.h等頭文件,可使用其它API代替


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章