我通过查看 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
枚举技术。但我看到这还不是最佳的:
我为提高性能所做的努力:
使用另一个标志打开文件,例如FILE_FLAG_SEQUENTIAL_SCAN
, FILE_FLAG_RANDOM_ACCESS
, or FILE_FLAG_NO_BUFFERING
:相同的结果:读取 21 秒
看着估计 NTFS 卷上的 USN 记录数 https://stackoverflow.com/questions/11336390/estimate-the-number-of-usn-records-on-ntfs-volume, 为什么在 VB.NET 中使用 DeviceIoControl 进行文件枚举比在 C++ 中更快? https://stackoverflow.com/questions/27393985/why-file-enumeration-using-deviceiocontrol-is-faster-in-vb-net-than-in-c我已经深入研究了它们,但它没有提供这个实际问题的答案。
测试另一个编译器:MinGW64 而不是 VC++ Express 2013:相同的性能结果,没有差异
在 VC++ 上,我已经切换到Release
代替Debug
:还有其他项目属性/选项可以加快程序速度吗?
Question:
是否可以提高性能DeviceIoControl(hDrive, FSCTL_ENUM_USN_DATA, ...)
?
或者是提高性能的唯一方法是对 NTFS 进行低级手动解析?
注:根据测试,这些期间读取的总大小DeviceIoControl(hDrive, FSCTL_ENUM_USN_DATA, ...)
对于我的 700k 文件来说是only84MB。读取 84MB 需要 21 秒,速度仅为 4 MB/秒(而且我确实有 SSD!)。性能可能还有一些改进的空间,您不这么认为吗?