2011-07-01 97 views
2

我实现了这个代码,但我再次无法搜索子目录。如何通过Delphi中的所有子目录搜索文件

 procedure TFfileSearch.FileSearch(const dirName:string); 
    begin 
//We write our search code here 
    if FindFirst(dirName,faAnyFile or faDirectory,searchResult)=0 then 
    begin 
    try 
     repeat 
     ShowMessage(IntToStr(searchResult.Attr)); 
     if (searchResult.Attr and faDirectory)=0 then //The Result is a File 
     //begin 
      lbSearchResult.Items.Append(searchResult.Name) 
     else 
     begin 
      FileSearch(IncludeTrailingBackSlash(dirName)+searchResult.Name); 
      // 
     end; 
     until FindNext(searchResult)<>0 
    finally 
    FindClose(searchResult); 
    end; 
    end; 
    end; 
    procedure TFfileSearch.btnSearchClick(Sender: TObject); 
    var 
filePath:string; 
begin 
lbSearchResult.Clear; 
if Trim(edtMask.Text)='' then 
    MessageDlg('EMPTY INPUT', mtWarning, [mbOK], 0) 
else 
begin 
    filePath:=cbDirName.Text+ edtMask.Text; 
    ShowMessage(filePath); 
    FileSearch(filePath); 

end; 

end;

我正在搜索E:\驱动器中的* .ini文件。所以最初filePath是E:*。ini。 但代码不搜索E:\驱动器中的目录。如何纠正?

由于提前

+0

http://stackoverflow.com/questions/ 6536525/how-to-search-a-file-through-all-the-sub-directory-in-delphi/6536733#6536733 –

回答

9

你不能限制适用于调用FindFirst文件扩展名。如果你这样做,那么目录不会枚举。相反,您必须在代码中检查匹配的扩展名。尝试是这样的:

procedure TMyForm.FileSearch(const dirName:string); 
var 
    searchResult: TSearchRec; 
begin 
    if FindFirst(dirName+'\*', faAnyFile, searchResult)=0 then begin 
    try 
     repeat 
     if (searchResult.Attr and faDirectory)=0 then begin 
      if SameText(ExtractFileExt(searchResult.Name), '.ini') then begin 
      lbSearchResult.Items.Append(IncludeTrailingBackSlash(dirName)+searchResult.Name); 
      end; 
     end else if (searchResult.Name<>'.') and (searchResult.Name<>'..') then begin 
      FileSearch(IncludeTrailingBackSlash(dirName)+searchResult.Name); 
     end; 
     until FindNext(searchResult)<>0 
    finally 
     FindClose(searchResult); 
    end; 
    end; 
end; 

procedure TMyForm.FormCreate(Sender: TObject); 
begin 
    FileSearch('c:\windows'); 
end; 
+5

只是为了澄清,*“你不能对文件扩展名应用限制”*,因为那时目录不会枚举。 –

+0

@Sertac谢谢。我不精确,并相应地更新了答案。 –

+0

另外,即使可以找到一个目录,比如说'C:\ SomeDir',也不可能搜索'C:\ *。ini \ SomeDir \'。 –

-2
procedure FindFilePattern(root:String;pattern:String); 
var 
    SR:TSearchRec; 
begin 
    root:=IncludeTrailingPathDelimiter(root); 
    if FindFirst(root+'*.*',faAnyFile,SR) = 0 then 
    begin 
     repeat 
      Application.ProcessMessages; 
      if ((SR.Attr and faDirectory) = SR.Attr) and (pos('.',SR.Name)=0) then 
      FindFilePattern(root+SR.Name,pattern) 
      else 
      begin 
      if pos(pattern,SR.Name)>0 then Form1.ListBox1.Items.Add(Root+SR.Name); 
      end; 
     until FindNext(SR)<>0; 
    end; 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    FindFilePattern('C:\','.exe'); 
end; 

这递归搜索,以显示包含某种模式的文件名的所有文件夹。

+0

此代码错误地比较了文件属性和名称,并且正在泄漏搜索句柄。 –

5

我讨厌使用FindFirst/FindNext的递归解决方案,我认为有些人甚至忘记使用FindClose来清理资源,这很麻烦。因此,对于它的乐趣,非递归的解决方案,应该是实际使用...

procedure FindDocs(const Root: string); 
var 
    SearchRec: TSearchRec; 
    Folders: array of string; 
    Folder: string; 
    I: Integer; 
    Last: Integer; 
begin 
    SetLength(Folders, 1); 
    Folders[0] := Root; 
    I := 0; 
    while (I < Length(Folders)) do 
    begin 
    Folder := IncludeTrailingBackslash(Folders[I]); 
    Inc(I); 
    { Collect child folders first. } 
    if (FindFirst(Folder + '*.*', faDirectory, SearchRec) = 0) then 
    begin 
     repeat 
     if not ((SearchRec.Name = '.') or (SearchRec.Name = '..')) then 
     begin 
      Last := Length(Folders); 
      SetLength(Folders, Succ(Last)); 
      Folders[Last] := Folder + SearchRec.Name; 
     end; 
     until (FindNext(SearchRec) <> 0); 
     FindClose(SearchRec); 
    end; 
    { Collect files next.} 
    if (FindFirst(Folder + '*.doc', faAnyFile - faDirectory, SearchRec) = 0) then 
    begin 
     repeat 
     if not ((SearchRec.Attr and faDirectory) = faDirectory) then 
     begin 
      WriteLn(Folder, SearchRec.Name); 
     end; 
     until (FindNext(SearchRec) <> 0); 
     FindClose(SearchRec); 
    end; 
    end; 
end; 

虽然现在看来,因为它使用一个动态数组吃大量的内存,递归方法将做完全一样,但递归发生在堆栈上!此外,通过递归方法,空间分配为全部局部变量,而我的解决方案仅为文件夹名称分配空间。
当您检查速度时,两种方法应该一样快。但递归方法更容易记住。你也可以使用TStringList而不是动态数组,但我只是喜欢动态数组。
我的解决方案还有一个技巧:它可以搜索多个文件夹!我只用一个根初始化文件夹数组,但可以很容易地将其长度设置为3,并将文件夹[0]设置为C:\,文件夹[1]为D:\,文件夹[2]为E:\并且它将在多个磁盘上搜索!

顺便说一句,用您要执行什么逻辑WriteLn()的代码...

+2

如果它没有使用'SetLength(..,Length()+ 1)',我会对它进行投票。 –

+0

'SetLength(..,Length()+ 1)'有什么问题?你愿意分配一个更大的缓冲区吗?使用链接列表? ot TStringList维护文件夹列表?有很多选择可供选择。 –

+2

一个字符串列表将是我的选择。 'SetLength(..,Length()+ 1)'很容易导致内存碎片。 –

1

我建议做如下:

uses 
    System.Types, 
    System.IOUtils; 

procedure TForm7.Button1Click(Sender: TObject); 
var 
    S: string; 
begin 
    Memo1.Lines.Clear; 
    for S in TDirectory.GetFiles('C:\test', '*.bmp', TSearchOption.soAllDirectories) do 
    Memo1.Lines.Add(S); 
    Showmessage('Pronto!'); 
end; 
+0

嗨!对你所粘贴的代码提供一些解释,这将是非常好的。谢谢! –

+0

尽管此代码片段可能会解决问题,但[包括解释](http://meta.stackexchange.com/questions/114762/explaining-entirely-code- based-answers)确实有助于提高您的质量帖子。请记住,您将来会为读者回答问题,而这些人可能不知道您的代码建议的原因。 –

相关问题