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代替


  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要输出新建文件的名字,你可以在监控到目录变化事件后,调用FindNextChangeNotification()函数获取目录变化信息,然后从信息中获取新创建的文件名。下面是一个示例代码: ``` #include <stdio.h> #include <windows.h> void monitorDirectoryChanges(const char* path) { HANDLE dirHandle = FindFirstChangeNotification(path, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME); if (dirHandle == INVALID_HANDLE_VALUE) { printf("Failed to monitor directory changes\n"); return; } while (TRUE) { DWORD waitStatus = WaitForSingleObject(dirHandle, INFINITE); if (waitStatus == WAIT_OBJECT_0) { char buffer[1024]; DWORD bufferSize = sizeof(buffer); DWORD bytesReturned = 0; BOOL success = ReadDirectoryChangesW( dirHandle, buffer, bufferSize, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME, &bytesReturned, NULL, NULL ); if (success) { FILE_NOTIFY_INFORMATION* fileInfo = (FILE_NOTIFY_INFORMATION*) buffer; while (fileInfo) { printf("A new file has been created in %s: %.*ls\n", path, fileInfo->FileNameLength / 2, fileInfo->FileName); fileInfo = fileInfo->NextEntryOffset > 0 ? (FILE_NOTIFY_INFORMATION*) ((BYTE*) fileInfo + fileInfo->NextEntryOffset) : NULL; } } else { printf("Failed to read directory changes\n"); break; } FindNextChangeNotification(dirHandle); } else { printf("Failed to wait for directory change notification\n"); break; } } FindCloseChangeNotification(dirHandle); } int main() { char path[] = "C:\\Some\\Directory"; monitorDirectoryChanges(path); return 0; } ``` 在上面的代码中,我们调用了ReadDirectoryChangesW()函数来读取目录变化信息。该函数会返回一个指向FILE_NOTIFY_INFORMATION结构体数组的指针,每个结构体对应一个目录变化事件,其中包含了新创建文件的文件名信息。我们可以通过遍历这个数组来获取所有目录变化事件的信息,从而输出新创建文件的名字。注意,这里使用了Unicode版本的ReadDirectoryChanges()函数,因为它可以正确处理中文字符。如果要处理英文字符,可以使用ReadDirectoryChangesA()函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值