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

前端之家收集整理的这篇文章主要介绍了delphi – 获取目录列表的最快方法是什么前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我需要以递归方式为给定的根/父路径构建一个树结构.像“浏览文件夹”对话框.

Delphi的FindFirst(FindFirstFile API)不能与faDirectory一起使用,FindNext将获取所有文件(它使用faAnyFile而不管指定的faDirectory),而不仅仅是目录.这使得构建树的过程非常缓慢.

有没有快速方法获取目录列表(树)而不使用FindFirst / FindNext?

解决方法

绝对最快的方式,使用 NtQueryDirectoryFile api.有了这个我们可以一次查询不是单个文件而是多个文件.还可以选择要返回的信息(较小的信息 – 更高的速度).示例(完全递归)
  1. // int nLevel,PSTR prefix for debug only
  2. void ntTraverse(POBJECT_ATTRIBUTES poa,int nLevel,PSTR prefix)
  3. {
  4. enum { ALLOCSIZE = 0x10000 };//64kb
  5.  
  6. if (nLevel > MAXUCHAR)
  7. {
  8. DbgPrint("nLevel > MAXUCHAR\n");
  9. return ;
  10. }
  11.  
  12. NTSTATUS status;
  13. IO_STATUS_BLOCK iosb;
  14. UNICODE_STRING ObjectName;
  15. OBJECT_ATTRIBUTES oa = { sizeof(oa),&ObjectName };
  16.  
  17. DbgPrint("%s[<%wZ>]\n",prefix,poa->ObjectName);
  18.  
  19. 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)))
  20. {
  21. if (PVOID buffer = new UCHAR[ALLOCSIZE])
  22. {
  23. union {
  24. PVOID pv;
  25. PBYTE pb;
  26. PFILE_DIRECTORY_INFORMATION DirInfo;
  27. };
  28.  
  29. while (0 <= (status = NtQueryDirectoryFile(oa.RootDirectory,NULL,pv = buffer,ALLOCSIZE,FileDirectoryInformation,FALSE)))
  30. {
  31.  
  32. ULONG NextEntryOffset = 0;
  33.  
  34. do
  35. {
  36. pb += NextEntryOffset;
  37.  
  38. ObjectName.Buffer = DirInfo->FileName;
  39.  
  40. switch (ObjectName.Length = (USHORT)DirInfo->FileNameLength)
  41. {
  42. case 2*sizeof(WCHAR):
  43. if (ObjectName.Buffer[1] != '.') break;
  44. case sizeof(WCHAR):
  45. if (ObjectName.Buffer[0] == '.') continue;
  46. }
  47.  
  48. ObjectName.MaximumLength = ObjectName.Length;
  49.  
  50. if (DirInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  51. {
  52. ntTraverse(&oa,nLevel + 1,prefix - 1);
  53. }
  54.  
  55. } while (NextEntryOffset = DirInfo->NextEntryOffset);
  56.  
  57. if (ALLOCSIZE - iosb.Information > (ULONG)FIELD_OFFSET(FILE_DIRECTORY_INFORMATION,FileName[256]))
  58. {
  59. break;//NO_MORE_FILES
  60. }
  61. }
  62.  
  63. delete [] buffer;
  64.  
  65. if (status == STATUS_NO_MORE_FILES)
  66. {
  67. status = STATUS_SUCCESS;
  68. }
  69. }
  70.  
  71. NtClose(oa.RootDirectory);
  72. }
  73.  
  74. if (0 > status)
  75. {
  76. DbgPrint("---- %x %wZ\n",status,poa->ObjectName);
  77. }
  78. }
  79.  
  80.  
  81.  
  82. void ntTraverse()
  83. {
  84. BOOLEAN b;
  85. RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE,TRUE,FALSE,&b);
  86.  
  87. char prefix[MAXUCHAR + 1];
  88. memset(prefix,'\t',MAXUCHAR);
  89. prefix[MAXUCHAR] = 0;
  90.  
  91. STATIC_OBJECT_ATTRIBUTES(oa,"\\systemroot");
  92. ntTraverse(&oa,prefix + MAXUCHAR);
  93. }

但是如果您使用交互式树 – 您不需要一次扩展所有树,但只需要顶层,使用TVE_EXPAND处理TVN_ITEMEXPANDING,使用TVE_COLLAPSE处理TVN_ITEMEXPANDED,以便在用户点击时设置扩展/折叠节点并设置cChildren

如果将FindFirstFileExW与FIND_FIRST_EX_LARGE_FETCH和FindExInfoBasic一起使用,这会给N4QueryDirectoryFile提供近似性能,但要小一点:

  1. WIN32_FIND_DATA fd;
  2. HANDLE hFindFile = FindFirstFileExW(L"..\\*",FindExInfoBasic,&fd,FindExSearchLimitToDirectories,FIND_FIRST_EX_LARGE_FETCH);
  3. if (hFindFile != INVALID_HANDLE_VALUE)
  4. {
  5. do
  6. {
  7. if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  8. {
  9. if (fd.cFileName[0] == '.')
  10. {
  11. switch (fd.cFileName[1])
  12. {
  13. case 0:
  14. continue;
  15. case '.':
  16. if (fd.cFileName[2] == 0) continue;
  17. break;
  18. }
  19. }
  20. DbgPrint("%S\n",fd.cFileName);
  21. }
  22. } while (FindNextFile(hFindFile,&fd));
  23.  
  24. FindClose(hFindFile);
  25. }

遗憾的是,FindExSearchLimitToDirectories目前尚未实现

猜你在找的Delphi相关文章