14

In my Application I use the following procedure to recursively scan any folder and subfolders, if the folder contains Text Files (*.txt) I add the filename to a TStringList defined in my procedure:

procedure FileSearch(const PathName: string; var lstFiles: TStringList);
const
  FileMask = '*.txt';
var
  Rec: TSearchRec;
  Path: string;
begin
  Path := IncludeTrailingBackslash(PathName);
  if FindFirst(Path + FileMask, faAnyFile - faDirectory, Rec) = 0 then
    try
      repeat
        lstFiles.Add(Path + Rec.Name);
      until FindNext(Rec) <> 0;
    finally
      FindClose(Rec);
    end;

  if FindFirst(Path + '*.*', faDirectory, Rec) = 0 then
    try
      repeat
        if ((Rec.Attr and faDirectory) <> 0) and (Rec.Name <> '.') and
          (Rec.Name <> '..') then
          FileSearch(Path + Rec.Name, lstFiles);
      until FindNext(Rec) <> 0;
    finally
      FindClose(Rec);
    end;
end;

Everything works perfect, but I want to be able to search for multiple file extensions. I have tried modifying the FileMask to do this but each time it returns nothing, likely because it is looking for an invalid extension. I have tried each of the following with no luck: (tried one at a time obviously, I did not write the below lines 3 times in my procedure)

FileMask = '*.txt|*.rtf|*.doc';

FileMask = '*.txt;*.rtf;*.doc';

FileMask = '*.txt,*.rtf,*.doc';

I feel silly for asking this, but how do I allow the extra file extensions to be included in the search? I can do it for Open and Save dialogs, why cant I separate the extensions here?

Thanks.

Craig.

2 Answers2

13

Change your function so it accepts a list of extensions as well, separated by semicolons or some other delimiter. You can then check the existence of each found file's extension in that list of extensions, and if it's found add it to your stringlist.

Something like this should work:

procedure FileSearch(const PathName: string; const Extensions: string;
 var lstFiles: TStringList);
const
  FileMask = '*.*';
var
  Rec: TSearchRec;
  Path: string;
begin
  Path := IncludeTrailingBackslash(PathName);
  if FindFirst(Path + FileMask, faAnyFile - faDirectory, Rec) = 0 then
    try
      repeat
        if AnsiPos(ExtractFileExt(Rec.Name), Extensions) > 0 then
          lstFiles.Add(Path + Rec.Name);
      until FindNext(Rec) <> 0;
    finally
      SysUtils.FindClose(Rec);
    end;

  if FindFirst(Path + '*.*', faDirectory, Rec) = 0 then
    try
      repeat
        if ((Rec.Attr and faDirectory) <> 0) and (Rec.Name <> '.') and
          (Rec.Name <> '..') then
          FileSearch(Path + Rec.Name, Extensions, lstFiles);
      until FindNext(Rec) <> 0;
    finally
      FindClose(Rec);
    end;
end;

Sample call:

FileSearch('C:\Temp', '.txt;.tmp;.exe;.doc', FileList);
Ken White
  • 117,855
  • 13
  • 197
  • 405
  • 1
    PathMatchSpec in AhLwApi might be a little cleaner than AnsiPos. http://msdn.microsoft.com/en-us/library/bb773727%28v=vs.85%29.aspx – Bruce McGee May 13 '11 at 12:15
  • 1
    @Bruce: You mean Shlwapi? PathMatchSpec appears to only check a single extension at a time, meaning you'd have to parse your list of extensions out separately to test. Using AnsiPos allows you to simply check to see if one is in the delimited list. If you're worried about case-sensitivity, you could use `AnsiContainsText` isntead; it performs a case-insensitive search and returns a Boolean indicating whether the substring exists or not. – Ken White May 13 '11 at 12:55
  • Yes, ShlwApi. PathMatchSpec's second parameter accepts multiple semicolon separated file extensions. – Bruce McGee May 13 '11 at 23:47
  • Chatty as it may be, I thought it was worth mentioning this is at least my 30th time visiting this link to copy this code to use. Out of all the examples out there, this is the most thorough and accurate description. – Jerry Dodge Mar 20 '13 at 23:30
0

In Delphi XE7 this line of code generates (line 17) an error:

finally
  SysUtils.FindClose(Rec);
end;

To correct the error I just deleted SysUtils. to read this code:

finally
  FindClose(Rec);
end;

Now the code compile fine. Thanks for this very useful code and solution.

  • I found something strange with this function. In term of search result. Let's pretend I have these files inside C:\temp: afile.m, asong.mp3,amovie.mp4 Now when I do a search. FileSearch('C:\Temp', '.*.mp3;*.mp4', FileList); Result inside the list are the 3 files and not the last 2 one. Why? – Benoit Standaert Feb 26 '16 at 19:31