我需要解析目录中的每个文件,包括子目录和子子目录中的文件和...
我已使用以下代码成功完成此操作:
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
来忽略任何无法访问的目录。
答案 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}}