如何尽可能快地创建CreateFile

Mac*_*ker 6 windows io performance file-io winapi

我需要在启动时阅读数千个小文件的内容.在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);
Run Code Online (Sandbox Code Playgroud)

Chr*_*ith 11

CreateFilekernel32.dll有一些额外的开销相比,内核系统调用NtCreateFilentdll.dll.这是CreateFile调用要求内核打开文件的真正函数.如果你需要打开大量文件,NtOpenFile那么通过避免Win32具有的特殊情况和路径转换将会更有效 - 无论如何这些内容都不适用于目录中的一堆文件.

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);
Run Code Online (Sandbox Code Playgroud)

主要缺点:Microsoft不支持此API用于用户模式.也就是说,内核模式使用时记录了等效函数,并且自1993年第一次发布Windows NT以来没有改变.

NtOpenFile 还允许您打开相对于现有目录句柄的文件(示例中的ParentDirectoryHandle),这应该减少定位目录时的一些文件系统开销.

最后,正如Carey Gregory所说,NTFS在处理包含大量文件的目录时可能太慢了.

  • 关于 NTFS“慢”的说法和 NtCreateFile 比 CreateFile 快的说法都不是真的 - 两者都完全是捏造的。除非有人发布一些证据来证明这一点,否则我将不得不称之为废话 - 除了几个 CPU 周期之外,这两个功能在夜间的表现将相同,而且 NTFS 是一个速度适中的文件系统。 (2认同)