我需要在启动时阅读数千个小文件的内容。在linux上,只需使用fopen和读取速度非常快。在Windows上,这种情况发生得非常缓慢。
我已经使用ReadFileEx切换到使用Overlapped I / O(异步I / O),其中Windows在数据准备好读取时进行回调。
但是,实际上对CreateFile本身的数千次调用仍然是一个瓶颈。请注意,我提供了自己的缓冲区,打开NO_BUFFERING标志,提供SERIAL提示等。但是,对CreateFile的调用需要几十秒的时间,而在Linux上,所有操作都要快得多。
有什么方法可以让这些文件准备好更快地阅读吗?
对CreateFile的调用是:
hFile = CreateFile(szFullFileName,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING | FILE_FLAG_SEQUENTIAL_SCAN,
NULL);
答案 0 :(得分:11)
CreateFile
中的{p> kernel32.dll
与NtCreateFile
中的内核系统调用ntdll.dll
相比有一些额外的开销。这是CreateFile
调用以请求内核打开文件的真正函数。如果你需要打开大量文件,那么通过避免Win32具有的特殊情况和路径转换,NtOpenFile
将更有效率 - 无论如何都不适用于目录中的一堆文件。< / p>
NTSYSAPI NTSTATUS NTAPI NtOpenFile(OUT HANDLE *FileHandle, IN ACCESS_MASK DesiredAccess, IN OBJECT_ATTRIBUTES *ObjectAttributes, OUT IO_STATUS_BLOCK *IoStatusBlock, IN ULONG ShareAccess, IN ULONG OpenOptions);
HANDLE Handle;
OBJECT_ATTRIBUTES Oa = {0};
UNICODE_STRING Name_U;
IO_STATUS_BLOCK IoSb;
RtlInitUnicodeString(&Name_U, Name);
Oa.Length = sizeof Oa;
Oa.ObjectName = &Name_U;
Oa.Attributes = CaseInsensitive ? OBJ_CASE_INSENSITIVE : 0;
Oa.RootDirectory = ParentDirectoryHandle;
Status = NtOpenFile(&Handle, FILE_READ_DATA, &Oa, &IoSb, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_SEQUENTIAL_ONLY);
主要缺点:Microsoft不支持此API用于用户模式。也就是说,自1993年第一次发布Windows NT以来,等效函数is documented for kernel mode use并未发生变化。
NtOpenFile
还允许您打开相对于现有目录句柄的文件(示例中的ParentDirectoryHandle),这应该减少定位目录时的一些文件系统开销。
最后,正如Carey Gregory所说,NTFS在处理包含大量文件的目录时可能太慢了。
答案 1 :(得分:0)
在发出创建文件之前,请在MFT中有效地进行分页。这可以通过发出FSCTL_ENUM_USN_DATA来完成。