我使用Free Pascal和Lazarus IDE编写了一个程序。简而言之,它以递归方式扫描每个文件的目录和“做东西”(散列),然后将散列值和文件名输出到StringGrid中,并使用每个连续文件刷新。
它适用于多达几千个文件,但是当你达到成千上万时,它确实变慢,每半秒处理一个文件,即使它只是一个几Kb的小文件。
负责代码的主要部分如下。任何人都可以看到为什么我的程序在网格中的文件数量超过数万时会变慢?
procedure TForm1.HashFile(FileIterator: TFileIterator);
var
SizeOfFile : int64;
NameOfFileToHash, fileHashValue, PercentageProgress : string;
FI : TFileIterator; //File Iterator class
SG : TStringGrid;
begin
FI := TFileIterator.Create;
SG := TStringGrid.Create(self);
SizeOfFile := 0;
fileHashValue := '';
if StopScan = FALSE then // If Stop button clicked, cancel scan
begin
NameOfFileToHash := (FileIterator.FileName);
SizeOfFile := FileSize(NameofFileToHash);
StatusBar1.SimpleText := 'Currently Hashing: ' + NameOfFileToHash;
fileHashValue := CalcTheHashFile(NameOfFileToHash); // Custom function, see below
// Now lets update the stringgrid and text fields
// StringGrid Elements:
// Col 0 is FileCounter. Col 1 is File Name. Col 2 is Hash
StringGrid1.rowcount:= FileCounter+1;
StringGrid1.Cells[0,FileCounter] := IntToStr(FileCounter);
Stringgrid1.Cells[1,FileCounter] := NameOfFileToHash;
Stringgrid1.Cells[2,FileCounter] := UpperCase(fileHashValue);
// Dynamically scroll the list so the user always has the most recently hashed
// file insight and expand the columns in lie with their content width
StringGrid1.row := FileCounter;
StringGrid1.col := 1;
StringGrid1.AutoSizeColumns;
// Progress Status Elements: Most of these vars are global vars
NoOfFilesExamined.Caption := IntToStr(FileCounter);
PercentageProgress := IntToStr((FileCounter * 100) DIV NoOfFilesInDir2);
Edit1.Caption := PercentageProgress + '%';
TotalBytesRead := TotalBytesRead + SizeOfFile;
edtTotalBytesExamined.Caption := FormatByteSize(TotalBytesRead);
Application.ProcessMessages;
FileCounter := FileCounter+1;
end;
SG.Free;
FI.Free;
end;
完整的源代码可以从我的SourceForge页面https://sourceforge.net/projects/quickhash/下的'Files' - >下获得。如果您需要,请使用“源代码”。
任何帮助表示赞赏
泰德
答案 0 :(得分:5)
作为德尔福的家伙,有两件事突然出现在我面前。 AutoSizeColumns。如果你很幸运,它什么都不做。如果它正在向下移动10,000行中的所有列,每次更新并执行GetTextLength以查看它是否适合,然后重新绘制网格....
因此,作业1将预设一些列大小并对其进行评论。 在扫描结束时最多执行一次。
谁想要一次看到所有10,000行?
我想我会将它们流式传输到文件中,并显示最后一页的完整内容以表明进度。然后我用文件驱动我的ui,使用一个简单的页面完整场景。 取决于您对数据的处理方式,但您可以重新加载文件以进行进一步分析,对比较进行比较。
即使你坚持在记忆中有一个TList? THashRecord。然后从那里开你的显示器,那么你将有机会。
答案 1 :(得分:1)
此外,大多数可视组件都有某种方法可以进行批量更新,如下所示:
Try
Grid1.BeginUpdate;
for Row := low(inputArray) to high(InputArray) do
Grid1.Append(InputArray[Row].data);
Finally
Grid1.EndUpdate;
end;
上面显然是伪代码,但是搜索组件的方法,例如BeginUpdate / EndUpdate。使用这些将防止对每一行进行无偿处理。即使您希望在填充时更新显示,也可以每10行或100行而不是每行进行更新。
(显然,您可以使用VirtualListbox等,而不是像其他人所提到的那样为每一行提供管理组织。)