我正在使用此代码来填充磁盘上所有文件的数据库:
TCHAR szVolumePath[_MAX_PATH] = L"\\\\.\\d:";
HANDLE hDrive = CreateFile(szVolumePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL);
MFT_ENUM_DATA_V0 med = { 0 };
med.StartFileReferenceNumber = 0;
med.LowUsn = 0;
med.HighUsn = MAXLONGLONG;
DWORD cb;
PUSN_RECORD pRecord;
unsigned char pData[sizeof(DWORDLONG) + 0x10000] = { 0 };
while (DeviceIoControl(hDrive, FSCTL_ENUM_USN_DATA, &med, sizeof(med), pData, sizeof(pData), &cb, NULL) != FALSE)
{
pRecord = (PUSN_RECORD)&pData[sizeof(USN)];
while ((PBYTE)pRecord < (pData + cb))
{
wstring sz((LPCWSTR)(PBYTE)pRecord + pRecord->FileNameOffset, pRecord->FileNameLength / sizeof(WCHAR));
// file the database
pRecord = (PUSN_RECORD)((PBYTE)pRecord + pRecord->RecordLength);
}
med.StartFileReferenceNumber = *(DWORDLONG *)pData;
}
一旦循环完成,数据库就被成功填充。
但是如何继续(作为后台任务)实时监控文件更改/删除?(例如:显示MessageBox()
“文件 readme.txt 已重命名。”)
我是否应该每 1 秒重新启动一次这样的循环,其中med.StartFileReferenceNumber
= 以前见过的最高 FileReferenceNumber?
注意:我有点不愿意每 1 秒启动一次此代码(99% 的时间,白费)。相反,每 10 秒执行一次可以避免使用这么多资源,但是在检测到更改之前会有延迟,而我确实知道一些没有这种延迟的索引软件。
注意2:我阅读了如何仅检测卷上已删除、更改和创建的文件?但主要答案的目的是运行一次,而不是一直在后台运行。
注意 3:我查看了 Microsoft Keeping an Eye on Your NTFS Drives 中的这个有用的代码示例:Windows 2000 Change Journal Explained。
注意4:我是否应该保留FSCTL_ENUM_USN_DATA用于初始数据库加载,然后使用FSCTL_READ_USN_JOURNAL代替?
注意5:ReadDirectoryChangesW
或者FindNextChangeNotification
(前者给出了通知中更改的完整路径,后者没有)不能真正使用,因为它不会给出FileReferenceNumber
已删除文件的 (必须打开文件并使用NtQueryInformationFile
才能获取它;但这对于已删除的文件是不可能的);并且 FileReferenceNumber 是更新文件数据库所必需的(文件数据库使用以 FileReferenceNumbers 作为键的映射/字典)。