12

TDirectory.GetFiles has a parameter called SearchPattern. Embarcadero's documentation says

The mask used when matching file names (for example, "*.exe" matches all the executable files).

However, I want to pass multiple file types. I get those types from a FilterComboBox.Mask. So, it is a string that looks like '*.txt;*.rtf;*.doc'.

I have tried to pass that string directly to GetFiles and it doesn't work. Do I have to parse it, break it into pieces and feed every individual piece to GetFiles?

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
Gabriel
  • 20,797
  • 27
  • 159
  • 293

1 Answers1

23

The RTL code behind GetFiles calls Masks.MatchesMask to test for a match to your search pattern. This function only supports masking against a single mask.

The alternative is to use the GetFiles overload that admits a TFilterPredicate. You supply a predicate that tests whether or not a name matches your pattern.

uses
  StrUtils, Types, Masks, IOUtils;

function MyGetFiles(const Path, Masks: string): TStringDynArray;
var
  MaskArray: TStringDynArray;
  Predicate: TDirectory.TFilterPredicate;
begin
  MaskArray := SplitString(Masks, ';');
  Predicate :=
    function(const Path: string; const SearchRec: TSearchRec): Boolean
    var
      Mask: string;
    begin
      for Mask in MaskArray do
        if MatchesMask(SearchRec.Name, Mask) then
          exit(True);
      exit(False);
    end;
  Result := TDirectory.GetFiles(Path, Predicate);
end;

Do note that MatchesMask creates and destroys a heap allocated TMask every time it is called. I can well imagine that being a performance bottleneck over a long search. In which case you could create an array of TMask objects from MaskArray. And use those in the predicate to test. I've no idea whether this is a valid concern or not, just something that occurred to me whilst perusing the code.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Nice one. +1 It sort of breaks when files with a semi-colon in the name are used, but that's not the fault of this routine. I never understood why they didn't use something like a pipe to separate masks. – Wouter van Nifterick Oct 04 '12 at 12:53
  • Yeah, obviously you can choose your sep char from one of the illegal file name chars – David Heffernan Oct 04 '12 at 12:54
  • Thanks. I know about predicates. I just wanted to make sure that there is indeed no function that directly supports multiple file types. – Gabriel Oct 04 '12 at 13:44
  • > I've no idea whether this is a valid concern or not - - - I guess it is since there are millions of files. Good catch. – Gabriel Oct 04 '12 at 14:59