提问人:LUN2 提问时间:9/25/2022 最后编辑:LUN2 更新时间:9/25/2022 访问量:663
使用 ReadDirectoryChangesW() 获取有关文件夹中新文件的信息
Using ReadDirectoryChangesW() to get information about new files in a folder
问:
晚上好!
我需要获取有关某些目录(Windows 10,C++)中新文件的信息。
为此,请执行以下操作:
- 我在重叠模式下调用 ReadDirectoryChangesW,并指出一个事件,以便在 ReadDirectoryChangesW 完成时发出信号
- 等到事件发出信号 (WaitForMultipleObjects)
- 调用 GetOverlappedResult 以获取有关新文件的 ReadDirectoryChangesW 信息。
上述所有操作都在循环中重复。
它运行良好,但是如果我同时创建两个或多个文件(复制多个文件并将它们粘贴到 Windows 资源管理器中),那么在步骤 (3) 中,我只会获得有关一个文件的信息。
但是,如果我重命名一个文件,那么我就会正确地从 ReadDirectoryChangesW 获得两条记录——关于旧文件名和新文件名。
ReadDirectoryChangesW 的缓冲区 (FILE_NOTIFY_INFORMATION) 可能不会溢出 – 我分配了 10 kb,有关新文件的信息约为 50-200 字节(它们的路径和名称足够短)。
如果我复制/粘贴 1 个文件,然后是 1 个文件等,则每次复制都会正常报告。
似乎只有当新文件出现“快速”(复制/粘贴多个文件)时,ReadDirectoryChangesW/GetOverlappedResult 才会返回有关 1 个文件的信息,但是我怎样才能获得有关其他文件的信息?
这是我的代码:
#include <iostream>
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <tchar.h>
#include <assert.h>
void RefreshDirectory(LPTSTR, HANDLE, DWORD);
void RefreshTree(LPTSTR, HANDLE, DWORD);
void WatchDirectory(LPTSTR);
int _tmain(int argc, TCHAR* argv[])
{
if (argc != 2)
{
_tprintf(TEXT("Usage: %s <dir>\n"), argv[0]);
return 0;
}
WatchDirectory(argv[1]);
}
/*#define FILE_ACTION_ADDED 0x00000001
#define FILE_ACTION_REMOVED 0x00000002
#define FILE_ACTION_MODIFIED 0x00000003
#define FILE_ACTION_RENAMED_OLD_NAME 0x00000004
#define FILE_ACTION_RENAMED_NEW_NAME 0x00000005 */
const WCHAR * ActionText[] = { L"-", L"file added", L"file removed", L"file modified", L"file ranamed (old)", L"file renamed (new)" };
#define MIN_ACTION_CODE 1
#define MAX_ACTION_CODE 5
void DisplayFileInfo(LPVOID FileInfoRecords, DWORD FileInfoLength) {
//ActionText[0] = L"-";
FILE_NOTIFY_INFORMATION* fi = (FILE_NOTIFY_INFORMATION*)FileInfoRecords;
if (FileInfoLength == 0) {
std::wcout << L"No file info!" << std::endl;
return;
}
int RecNum = 1;
DWORD OffsetToNext = 0;
do {
// next record
fi = (FILE_NOTIFY_INFORMATION*)(((char*)fi) + OffsetToNext);
std::wstring wfname;
std::wstring wActionName;
if ((fi->Action < MIN_ACTION_CODE) || (fi->Action > MAX_ACTION_CODE))
wActionName = L"Unknown code";
else
wActionName = ActionText[fi->Action];
int slen = fi->FileNameLength / sizeof(WCHAR);
wfname.assign(fi->FileName, slen);
// output information about files changes
std::wcout << L"Rec " << RecNum << L": Action = " << wActionName << L"(" << fi->Action << L") Offset = " << fi->NextEntryOffset <<
L" File = " << wfname << std::endl;
OffsetToNext = fi->NextEntryOffset;
assert(RecNum < 50);
RecNum++;
} while (OffsetToNext > 0);
}
void WatchDirectory(LPTSTR lpDir)
{
DWORD dwWaitStatus;
HANDLE dwChangeHandles[2];
TCHAR lpDrive[4];
TCHAR lpFile[_MAX_FNAME];
TCHAR lpExt[_MAX_EXT];
std::wcout << L"Watchng for: " << lpDir << std::endl;
// split the path from parameters
_tsplitpath_s(lpDir, lpDrive, 4, NULL, 0, lpFile, _MAX_FNAME, lpExt, _MAX_EXT);
lpDrive[2] = (TCHAR)'\\';
lpDrive[3] = (TCHAR)'\0';
int EventsNumber = 1;
// flags for ReadDirectoryChangesW
DWORD Flags = FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_FILE_NAME;
// create a handle for a directory to look for
HANDLE hDir = CreateFile(lpDir, GENERIC_READ, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, NULL);
if (hDir == INVALID_HANDLE_VALUE) {
DWORD err = GetLastError();
std::wcout << L"ERROR: CreateFile(folder to trace) function failed = " << err << std::endl;
ExitProcess(err);
}
// --- initialyze data for ReadDirectoryChangesW ---
DWORD nBufferLength = 10000;
LPVOID lpBuffer = malloc(nBufferLength);
BOOL bWatchSubtree = TRUE;
DWORD BytesReturned = 0;
// --- create an event for "Overlapped" ---
HANDLE hEvent = CreateEvent(NULL, FALSE /*manual reset = true*/, FALSE /* initial state*/, NULL);
if (hEvent == NULL)
{
printf("\n Cannot create event.\n");
ExitProcess(GetLastError());
}
bool first = true;
while (TRUE)
{
// Wait for notification.
// =============================================================
OVERLAPPED Overlapped;
Overlapped.hEvent = hEvent;
LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine = NULL;
// request info about changes in overlapped-mode
BOOL res_rdc = ReadDirectoryChangesW(hDir,
lpBuffer,
nBufferLength,
bWatchSubtree,
Flags,
&BytesReturned,
&Overlapped,
lpCompletionRoutine);
bool ok_rdc = (res_rdc != 0);
if (ok_rdc) {
if (first)
printf("\nWaiting for notification...\n");
// wait for overlapped-function
dwChangeHandles[0] = Overlapped.hEvent;
dwWaitStatus = WaitForMultipleObjects(EventsNumber, dwChangeHandles,
FALSE, 3000);
switch (dwWaitStatus) {
case WAIT_OBJECT_0: {
printf("\n WAIT_OBJECT_0 .\n");
DWORD NumberOfBytesTransferred = 0;
BOOL ok_gor = GetOverlappedResult(hDir, &Overlapped, &NumberOfBytesTransferred, FALSE);
if (ok_gor == 0) {
//
DWORD err = GetLastError();
if (err == ERROR_IO_INCOMPLETE)
std::wcout << L"Err (GetOverlappedResult) = ERROR_IO_INCOMPLETE" << std::endl;
else
std::wcout << L"Err (GetOverlappedResult) = " << err << std::endl;
}
else {
// overplapped function(ReadDirectoryChangesW) exits normally
std::wcout << L"GetOverlappedResult = OK. Bytes = " << NumberOfBytesTransferred << std::endl;
// display files changes, received from ReadDirectoryChangesW
DisplayFileInfo(lpBuffer, NumberOfBytesTransferred /*FileInfoLength*/);
}
break;
}
case WAIT_TIMEOUT:
//
if (first)
printf("\nNo changes in the timeout period.\n");
break;
default:
printf("\n ERROR: Unhandled dwWaitStatus.\n");
ExitProcess(GetLastError());
break;
}
}
else {
// ошибка
DWORD err = GetLastError();
std::wcout << L"ReadDirectoryChangesW error = " << err << std::endl;
}
// =============================================================
first = false;
}
free(lpBuffer);
}
答: 暂无答案
评论
FindFirstChangeNotification
FindNextChangeNotification