Delphi 解析目录和子目录中的所有文件时出现IdFTP性能问题
我需要解析目录中的每个文件,包括子目录和子目录中的文件以及…Delphi 解析目录和子目录中的所有文件时出现IdFTP性能问题,delphi,indy,ftp-client,indy10,Delphi,Indy,Ftp Client,Indy10,我需要解析目录中的每个文件,包括子目录和子目录中的文件以及… 我已经使用下面的代码成功地完成了此操作: class function TATDFTPUtility.findAllDirectoryFiles(var ftpClient: TIdFTP; directory: String; deepness: Integer = 0): TidFTPListItems; var I: Integer; localDirectoryListing: TIdFTPListItems; b
我已经使用下面的代码成功地完成了此操作:
class function TATDFTPUtility.findAllDirectoryFiles(var ftpClient: TIdFTP; directory: String; deepness: Integer = 0): TidFTPListItems;
var
I: Integer;
localDirectoryListing: TIdFTPListItems;
baseDirectory: string;
begin
Result := TIdFTPListItems.Create;
*// this function uses ftpClient.ChangeDirUp until it reaches the '' directory*
changeUpToDirectory(ftpClient, '');
try
ftpClient.ChangeDir(directory);
ftpClient.List;
Result.Assign(ftpClient.DirectoryListing);
localDirectoryListing := Result;
baseDirectory := ftpClient.RetrieveCurrentDir;
for I := 0 to localDirectoryListing.Count - 1 do
begin
if (localDirectoryListing.Items[i].ItemType = ditDirectory) then
begin
result := addTwoFTPListItems(result, findAllDirectoryFiles(ftpClient, baseDirectory + '/' + localDirectoryListing.Items[i].FileName));
end;
end;
except
end;
end;
class function TATDFTPUtility.addTwoFTPListItems(listA: TIdFTPListItems; listB: TIdFTPListItems): TidFTPListItems;
var
i: integer;
begin
Result := listA;
for I := 0 to listB.Count - 1 do
begin
with Result.Add do
begin
Data := listB.Items[i].data;
Size := listB.Items[i].Size;
ModifiedDate := listB.Items[i].ModifiedDate;
LocalFileName := listB.Items[i].LocalFileName;
FileName := listB.Items[i].FileName;
ItemType := listB.Items[i].ItemType;
SizeAvail := listB.Items[i].SizeAvail;
ModifiedAvail := listB.Items[i].ModifiedAvail;
PermissionDisplay := listB.Items[i].PermissionDisplay;
end;
end;
end;
现在的问题是这大约需要15-20分钟强>
还有更有效的方法吗?以下是关于这个特殊案例的一些事实:
1-在我运行程序后,它发现了大约12000个文件,几乎有100-200个目录,但最高深度约为7
2-我只需要解析,不需要下载或上传任何内容
3-我使用异常的原因是,在FTP内部有一些我无权访问的文件夹,这导致
IdFTP中出现访问冲突错误,我使用尝试…除了忽略任何无法访问的目录。您正在调用ChangeDirUp()
(可能多次?)然后调用ChangeDir()
。如果directory
是一个绝对路径,您只需调用ChangeDir()
一次即可直接跳转到目标文件夹,并避免ChangeDirUp()
的全部调用。findAllDirectoryFiles()中的递归循环
正在使用来自RetrieveCurrentDir()
的绝对路径,因此重复调用ChangeDirUp()
和ChangeDir()
会浪费开销。不必在文件夹树上下导航,可以大大减少开销
findAllDirectoryFiles()
正在返回调用方必须释放的新分配的tidftplitiems
。这本身通常是一个糟糕的设计选择,但在这种情况下尤其如此,因为递归循环根本没有释放那些次要的tidftplitiems
对象,所以它们被泄漏
将文件添加到输出TIdFTPListItems
时,您只添加了文件名而不是路径。如果调用者不知道每个文件的位置,递归搜索文件有什么好处?或者您只关心文件名而不关心路径
您完全忽略了深度
参数
话虽如此,请尝试类似的方法:
class procedure TATDFTPUtility.findAllDirectoryFiles(ftpClient: TIdFTP; const directory: String;var files: TIdFTPListItems; deepness: Integer = -1);
var
I: Integer;
baseDirectory: string;
subDirectories: TStringList;
item: TIdFTPListItem;
localDirectoryListing: TIdFTPListItems;
begin
try
if directory <> '' then
ftpClient.ChangeDir(directory);
ftpClient.List;
except
Exit;
end;
baseDirectory := ftpClient.RetrieveCurrentDir;
localDirectoryListing := ftpClient.DirectoryListing;
subDirectories := nil;
try
for I := 0 to localDirectoryListing.Count - 1 do
begin
case localDirectoryListing[i].ItemType of
ditFile: begin
item := files.Add;
item.Assign(localDirectoryListing[i]);
// if you need the full path of each file...
item.FileName := baseDirectory + '/' + item.FileName;
end;
ditDirectory: begin
item := localDirectoryListing[i];
if ((item.FileName <> '.') and (item.FileName <> '..')) and
((deepness = -1) or (deepness > 0)) then
begin
if subDirectories = nil then
subDirectories := TStringList.Create;
subDirectories.Add(baseDirectory + '/' + item.FileName);
end;
end;
end;
end;
if subDirectories <> nil then
begin
if (deepness > 0) then Dec(deepness);
for I := 0 to subDirectories.Count - 1 do begin
findAllDirectoryFiles(ftpClient, subDirectories[I], files, deepness);
end;
end;
finally
subDirectories.Free;
end;
end;
谢谢你的回答!我不知道我可以使用绝对路径,我不需要使用changeDirUp
!我还没有植入深度,这就是为什么它没有做任何事情,现在回到你的回答,我尝试了你的代码,当你调用findAllDirectoryFiles()时,有一些问题
您正在使目录列表无效,这就是为什么我使用了一个额外的FTPListItems
并分配了值,我对此进行了迭代,第二个必须是J
,最重要的是还有一个逻辑错误!程序永远运行!!,我记录了它并注意到(阅读下一条评论)您额外的tidftplitiems
对象是不必要的。此外,您建议的更改引入了新的内存泄漏,因此我已删除该更改。至于原始目录列表
在子目录
循环期间无效,这是因为我将该循环放在错误的位置。我现在已修复该问题(不需要额外的TIdFTPListItems
对象副本).我注意到程序永远运行!我记录了它,看到它在进入文件夹和找到文件后循环返回,它出现一层,进入相同的文件夹并再次查看它们!我认为它只是无限地在最后两层循环,如果可以的话,我将尝试调试该函数。尝试最新的代码。它是不应重新扫描以前扫描过的文件夹(除非服务器碰巧正在使用重定向到文件夹层次结构中更高级别的文件夹的虚拟文件夹。但以前没有听说过,但也不常见)。我刚刚运行了您的代码,前面的问题已经解决,我的日志显示“已解析文件计数=11587已解析文件夹计数=689”,这花费了16分钟!似乎每20个文件大约需要1秒,是否有可能更快的方法?
files := TIdFTPListItems.Create;
try
TATDFTPUtility.findAllDirectoryFiles(ftpClient, 'desired directory', files, desired deepness);
// use files as needed...
finally
files.Free;
end;