我通过查看NTFS MFT / USN期刊来枚举NTFS硬盘分区的文件:
HANDLE hDrive = CreateFile(szVolumePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL);
DWORD cb = 0;
MFT_ENUM_DATA med = { 0 };
med.StartFileReferenceNumber = 0;
med.LowUsn = 0;
med.HighUsn = MAXLONGLONG; // no change in perf if I use med.HighUsn = ujd.NextUsn; where "USN_JOURNAL_DATA ujd" is loaded before
unsigned char pData[sizeof(DWORDLONG) + 0x10000] = { 0 }; // 64 kB
while (DeviceIoControl(hDrive, FSCTL_ENUM_USN_DATA, &med, sizeof(med), pData, sizeof(pData), &cb, NULL))
{
med.StartFileReferenceNumber = *((DWORDLONG*) pData); // pData contains FRN for next FSCTL_ENUM_USN_DATA
// here normaly we should do: PUSN_RECORD pRecord = (PUSN_RECORD) (pData + sizeof(DWORDLONG));
// and a second loop to extract the actual filenames
// but I removed this because the real performance bottleneck
// is DeviceIoControl(m_hDrive, FSCTL_ENUM_USN_DATA, ...)
}
它有效,它比通常的FindFirstFile
枚举技术快得多。但我看到它还不是最佳:
在我的700k文件C:\
上,需要21秒。 (此措施必须在重新启动后完成,否则,由于缓存而不正确)。
我见过另一个索引软件(不是Everything,另一个)能够在<中找到C:\
5秒(在Windows启动后测量),无需读取.db文件中的预先计算的数据库(或其他类似的技巧,可以加快速度!)。该软件不使用FSCTL_ENUM_USN_DATA
,而是使用低级NTFS解析。
我试图提高效果:
使用其他标记打开文件,例如FILE_FLAG_SEQUENTIAL_SCAN
,FILE_FLAG_RANDOM_ACCESS
或FILE_FLAG_NO_BUFFERING
:相同结果:21秒阅读
查看Estimate the number of USN records on NTFS volume,Why file enumeration using DeviceIoControl is faster in VB.NET than in C++? 我已经深入研究了它们,但它没有提供这个实际问题的答案。
测试另一个编译器:MinGW64而不是VC ++ Express 2013:相同的性能结果,没有区别
在VC ++上,我已经切换到Release
而不是Debug
:还有其他项目属性/选项可以加快程序吗?
问题:
是否可以提高效果DeviceIoControl(hDrive, FSCTL_ENUM_USN_DATA, ...)
?
或是提高性能以进行NTFS的低级手动解析的唯一方法?
注意:根据测试,在这些{700}文件的DeviceIoControl(hDrive, FSCTL_ENUM_USN_DATA, ...)
期间要读取的总大小仅 84MB。 21秒读取84MB只有4 MB /秒(我确实有一个SSD!)。可能还有一些提升绩效的空间,你不这么认为吗?