gpt4 book ai didi

delphi - 仅获取目录列表的最快方法是什么

转载 作者:行者123 更新时间:2023-12-03 14:51:32 29 4
gpt4 key购买 nike

我需要为给定的根/父路径目录递归构建树结构。 类似“浏览文件夹”对话框的内容。

Delphi 的 FindFirst ( FindFirstFile API) 无法与 faDirectory 配合使用,而 FindNext 将获取所有文件(它使用 faAnyFile 无论指定faDirectory)而不仅仅是目录。这使得构建树的过程非常缓慢。

是否有一种无需使用 FindFirst/FindNext 即可快速获取目录列表(树)的方法?

最佳答案

绝对最快的方法,使用 NtQueryDirectoryFile API。这样我们就可以一次查询多个文件而不是单个文件。还选择将返回哪些信息(较小的信息 - 较高的速度)。示例(完全递归)

// int nLevel, PSTR prefix for debug only
void ntTraverse(POBJECT_ATTRIBUTES poa, int nLevel, PSTR prefix)
{
enum { ALLOCSIZE = 0x10000 };//64kb

if (nLevel > MAXUCHAR)
{
DbgPrint("nLevel > MAXUCHAR\n");
return ;
}

NTSTATUS status;
IO_STATUS_BLOCK iosb;
UNICODE_STRING ObjectName;
OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, &ObjectName };

DbgPrint("%s[<%wZ>]\n", prefix, poa->ObjectName);

if (0 <= (status = NtOpenFile(&oa.RootDirectory, FILE_GENERIC_READ, poa, &iosb, FILE_SHARE_VALID_FLAGS,
FILE_SYNCHRONOUS_IO_NONALERT|FILE_OPEN_REPARSE_POINT|FILE_OPEN_FOR_BACKUP_INTENT)))
{
if (PVOID buffer = new UCHAR[ALLOCSIZE])
{
union {
PVOID pv;
PBYTE pb;
PFILE_DIRECTORY_INFORMATION DirInfo;
};

while (0 <= (status = NtQueryDirectoryFile(oa.RootDirectory, NULL, NULL, NULL, &iosb,
pv = buffer, ALLOCSIZE, FileDirectoryInformation, 0, NULL, FALSE)))
{

ULONG NextEntryOffset = 0;

do
{
pb += NextEntryOffset;

ObjectName.Buffer = DirInfo->FileName;

switch (ObjectName.Length = (USHORT)DirInfo->FileNameLength)
{
case 2*sizeof(WCHAR):
if (ObjectName.Buffer[1] != '.') break;
case sizeof(WCHAR):
if (ObjectName.Buffer[0] == '.') continue;
}

ObjectName.MaximumLength = ObjectName.Length;

if (DirInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
ntTraverse(&oa, nLevel + 1, prefix - 1);
}

} while (NextEntryOffset = DirInfo->NextEntryOffset);
}

delete [] buffer;

if (status == STATUS_NO_MORE_FILES)
{
status = STATUS_SUCCESS;
}
}

NtClose(oa.RootDirectory);
}

if (0 > status)
{
DbgPrint("---- %x %wZ\n", status, poa->ObjectName);
}
}



void ntTraverse()
{
BOOLEAN b;
RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, TRUE, FALSE, &b);

char prefix[MAXUCHAR + 1];
memset(prefix, '\t', MAXUCHAR);
prefix[MAXUCHAR] = 0;

STATIC_OBJECT_ATTRIBUTES(oa, "\\systemroot");
ntTraverse(&oa, 0, prefix + MAXUCHAR);
}

但如果您使用交互式树 - 您不需要一次展开所有树,而只需展开顶层,请使用 TVE_EXPANDTVN_ITEMEXPANDED 处理 TVN_ITEMEXPANDING > 使用 TVE_COLLAPSE 在用户单击时展开/折叠节点并设置 cChildren

如果将 FindFirstFileExWFIND_FIRST_EX_LARGE_FETCHFindExInfoBasic 一起使用,这会提供接近 NtQueryDirectoryFile 的性能,但稍小一些:

WIN32_FIND_DATA fd;
HANDLE hFindFile = FindFirstFileExW(L"..\\*", FindExInfoBasic, &fd, FindExSearchLimitToDirectories, 0, FIND_FIRST_EX_LARGE_FETCH);
if (hFindFile != INVALID_HANDLE_VALUE)
{
do
{
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
if (fd.cFileName[0] == '.')
{
switch (fd.cFileName[1])
{
case 0:
continue;
case '.':
if (fd.cFileName[2] == 0) continue;
break;
}
}
DbgPrint("%S\n", fd.cFileName);
}
} while (FindNextFile(hFindFile, &fd));

FindClose(hFindFile);
}

不幸的是,FindExSearchLimitToDirectories 目前尚未实现

关于delphi - 仅获取目录列表的最快方法是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44658284/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com