目前我正在做這樣的事情:
var
Files: TArray<String>;
if IncludeSubDirs then
Files := TDirectory.GetFiles(Path, '*.exe', TSearchOption.soAllDirectories)
else
Files := TDirectory.GetFiles(Path, '*.exe', TSearchOption.soTopDirectoryOnly);
Path是用戶定義String的,可以指向任何現有目錄。對于具有大量檔案和IncludeSubDirs = True(例如 C:\Windows\)的“大”目錄GetFiles需要很長時間(例如 30 多秒)。
使用Delphi(如果有的話)在Windows下的“大”目錄中列出所有exe檔案的最快方法是什么?
uj5u.com熱心網友回復:
我做了一些基準測驗,對于一個巨大的目錄FindFirst/FindNext比使用TDirectory. 我會說兩者的速度相當(對于我的用例,我每分鐘節省了大約 1 秒)。我最終使用了FindFirst/FindNext因為您是逐步獲得結果而不是一次全部獲得結果,因此記憶體管理似乎更好,并且中途取消更容易。我還使用了 aTThread來避免阻塞我的 UI。
這就是我最終的結果:
procedure TDirectoryWorkerThread.AddToTarget(const Item: String);
begin
if (not Self.Parameters.DistinctResults) or (Self.Target.IndexOf(Item) = -1) then
Self.Target.Add(Item);
end;
procedure TDirectoryWorkerThread.ListFilesDir(Directory: String);
var
SearchResult: TSearchRec;
begin
Directory := IncludeTrailingPathDelimiter(Directory);
if FindFirst(Directory '*', faAnyFile, SearchResult) = 0 then
begin
try
repeat
if (SearchResult.Attr and faDirectory) = 0 then
begin
if (Self.Parameters.AllowedExtensions = nil) or (Self.Parameters.AllowedExtensions.IndexOf(ExtractFileExt(SearchResult.Name)) <> -1) then
AddToTarget(Directory SearchResult.Name);
end
else if Self.Parameters.IncludeSubDirs and (SearchResult.Name <> '.') and (SearchResult.Name <> '..') then
ListFilesDir(Directory SearchResult.Name);
until Self.Terminated or (FindNext(SearchResult) <> 0);
finally
FindClose(SearchResult);
end;
end;
end;
uj5u.com熱心網友回復:
最快的方法是虛擬化串列并使用 Windows API。此代碼摘錄僅顯示檔案名。用 D11 測驗。“ListView”必須有屬性“OwnerData = True”,使用方法“onData”和“ViewStyle = vsReport”。在“Edit1.Text”中有要顯示的檔案夾。
USES ShlObj, ComObj, ActiveX
TYPE PShellItem = ^TShellItem;
TShellItem = Record
FullID : PItemIDList;
ID : PItemIDList;
Empty : Boolean;
DisplayName : String;
TypeName : String;
ImageIndex : Integer;
Size : Integer;
Attributes : Integer;
ModDate : String;
End;
TForm1 = class(TForm)
Button1: TButton;
ListView: TListView;
Edit1: TEdit;
procedure Button1Click(Sender: TObject);
procedure ListViewData(Sender: TObject; Item: TListItem);
private
FIDesktopFolder : IShellFolder;
FIShellFolder : IShellFolder;
FIDList : TList;
PROCEDURE SetPath(ID : PItemIDList);
PROCEDURE PopulateIDList(ShellFolder : IShellFolder);
FUNCTION ShellItem(Index : Integer) : PShellItem;
public
end;
[...]
procedure TForm1.Button1Click(Sender: TObject);
VAR P : PWideChar;
NewPIDL : PItemIDList;
Flags : LongWord;
NumChars : LongWord;
begin
OLECheck(SHGetDesktopFolder(FIDesktopFolder));
FIDList := TList.Create;
NumChars := Length(Edit1.Text);
Flags := 0;
P := StringToOleStr(Edit1.Text);
OLECheck(FIDesktopFolder.ParseDisplayName(Application.Handle,nil,P,NumChars,NewPIDL,Flags));
SetPath(NewPIDL);
end;
PROCEDURE TForm1.SetPath(ID: PItemIDList);
VAR NewShellFolder : IShellFolder;
BEGIN
OLECheck(FIDesktopFolder.BindToObject(ID,nil,IID_IShellFolder,Pointer(NewShellFolder)));
ListView.Items.BeginUpdate;
Try PopulateIDList(NewShellFolder);
If ListView.Items.Count>0 Then
Begin
ListView.Selected := ListView.Items[0];
ListView.Selected.Focused := True;
ListView.Selected.MakeVisible(False);
End;
Finally
ListView.Items.EndUpdate;
End;
END;
PROCEDURE TForm1.PopulateIDList(ShellFolder: IShellFolder);
CONST Flags = SHCONTF_FOLDERS or SHCONTF_NONFOLDERS or SHCONTF_INCLUDEHIDDEN; //cartelle
Flags1 = SHCONTF_NONFOLDERS or SHCONTF_INCLUDEHIDDEN; //senza cartelle
VAR ID : PItemIDList;
EnumList : IEnumIDList;
NumIDs : LongWord;
SaveCursor : TCursor;
ShellItem : PShellItem;
function GetDisplayName(ShellFolder : IShellFolder;
PIDL : PItemIDList): string;
var StrRet : TStrRet;
P : PChar;
Flags : Integer;
begin
Result := '';
Flags := SHGDN_FORPARSING; //per vedere le estensioni anche quando sono nascoste
ShellFolder.GetDisplayNameOf(PIDL, Flags, StrRet);
case StrRet.uType Of
STRRET_CSTR : SetString(Result, StrRet.cStr, Length(StrRet.cStr));
STRRET_OFFSET : Begin
P:[email protected][StrRet.uOffset-SizeOf(PIDL.mkid.cb)];
SetString(Result,P,PIDL.mkid.cb-StrRet.uOffset);
End;
STRRET_WSTR : Result:=StrRet.pOleStr;
end;
Result := ExtractFileName(Result); //solo il nome
end;
BEGIN
SaveCursor := Screen.Cursor;
Try Screen.Cursor := crHourglass;
OleCheck(ShellFolder.EnumObjects(Application.Handle,Flags1,EnumList));
FIShellFolder := ShellFolder;
While EnumList.Next(1,ID,NumIDs)=S_OK do
Begin
ShellItem := New(PShellItem);
ShellItem.ID := ID;
ShellItem.DisplayName := GetDisplayName(ShellFolder,ID);
ShellItem.Empty := True;
FIDList.Add(ShellItem);
End;
ListView.Items.Count := FIDList.Count;
ListView.Repaint;
Finally
Screen.Cursor:=SaveCursor;
End;
END;
FUNCTION TForm1.ShellItem(Index : Integer) : PShellItem;
BEGIN
Result := PShellItem(FIDList[Index]);
END;
function IsFolder(ShellFolder: IShellFolder; ID: PItemIDList): Boolean;
var Flags : UINT;
begin
Flags := SFGAO_FOLDER;
ShellFolder.GetAttributesOf(1, ID, Flags);
Result := SFGAO_FOLDER and Flags <> 0;
end;
procedure TForm1.ListViewData(Sender: TObject; Item: TListItem);
var Attrs : string;
begin
if (Item.Index>FIDList.Count) then Exit;
with ShellItem(Item.Index)^ do
begin
Item.Caption := DisplayName;
Item.ImageIndex := ImageIndex;
if ListView.ViewStyle<>vsReport then Exit;
if not IsFolder(FIShellFolder, ID)
then Item.SubItems.Add(IntToStr(Size) ' Kb')
else Item.SubItems.Add('');
Item.SubItems.Add(TypeName);
try Item.SubItems.Add(ModDate);
except
end;
if Bool(Attributes and FILE_ATTRIBUTE_READONLY) then Attrs:=Attrs 'R';
if Bool(Attributes and FILE_ATTRIBUTE_HIDDEN) then Attrs:=Attrs 'H';
if Bool(Attributes and FILE_ATTRIBUTE_SYSTEM) then Attrs:=Attrs 'S';
if Bool(Attributes and FILE_ATTRIBUTE_ARCHIVE) then Attrs:=Attrs 'A';
end;
Item.SubItems.Add(Attrs);
end;
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/424527.html
標籤:视窗 德尔福 delphi-10.4-悉尼
