解析目录和子目录中的所有文件时的IdFTP性能问题

时间:2016-11-16 11:46:42

标签: delphi indy ftp-client indy10

我需要解析目录中的每个文件,包括子目录和子子目录中的文件和...
我已使用以下代码成功完成此操作:

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内部有一些我无法访问的文件夹,这导致access violation出现IdFTP错误而我使用了try...except来忽略任何无法访问的目录。

1 个答案:

答案 0 :(得分:3)

您正在调用ChangeDirUp()(可能多次?),然后再调用ChangeDir()。如果directory是绝对路径,则只需调用ChangeDir()一次即可直接跳转到目标文件夹,并完全避免ChangeDirUp()findAllDirectoryFiles()内部的递归循环使用来自RetrieveCurrentDir()的绝对路径,因此重复调用ChangeDirUp()ChangeDir()会浪费开销。通过不必要地在文件夹树中上下导航,可以大大减少开销。

findAllDirectoryFiles()返回一个新分配的TIdFTPListItems,调用者必须释放该TIdFTPListItems。这本身通常是一个糟糕的设计选择,但特别是在这种情况下,因为递归循环根本没有释放那些辅助TIdFTPListItems对象,所以它们被泄露。

将文件添加到输出deepness时,您只是添加文件名而不是其路径。如果调用者不知道每个文件的位置,那么递归搜索文件有什么用?或者您只关心文件名而不关心路径?

您完全忽略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; 参数。

话虽如此,请尝试更像这样的事情:

findAllDirectoryFiles()

首次致电directory时,您可以将deepness设置为:

  • 一个空白字符串,用于开始在当前目录中搜索。

  • 相对于当前目录的子文件夹。

  • 相对于服务器根目录的绝对文件夹。

并将files := TIdFTPListItems.Create; try TATDFTPUtility.findAllDirectoryFiles(ftpClient, 'desired directory', files, desired deepness); // use files as needed... finally files.Free; end; 设置为

  • -1表示无限递归

  • &gt; = 0指定递归的深度。

{{1}}