Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

File Masking in delphi

Tags:

delphi

mask

I am trying to find all files that have the extenstion .cbr or .cbz

If i set my mask to *.cb?

it finds *.cbproj files. How can i set the mask to only find .cbr and .cbz files?

here is code i am using.

I have two edit boxes EDIT1 is the location to search, EDIT2 is where i put my mask. A listbox to show what it found and a Search button.

edit1 := c:\
edit2 := mask (*.cb?)

space

    procedure TFAutoSearch.FileSearch(const PathName, FileName : string; const InDir : boolean);
var Rec  : TSearchRec;
    Path : string;
begin
Path := IncludeTrailingBackslash(PathName);
if FindFirst(Path + FileName, faAnyFile - faDirectory, Rec) = 0 then
 try
   repeat
     ListBox1.Items.Add(Path + Rec.Name);
   until FindNext(Rec) <> 0;
 finally
   FindClose(Rec);
 end;

If not InDir then Exit;

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, FileName, True);
   until FindNext(Rec) <> 0;
 finally
   FindClose(Rec);
 end;
end; //procedure FileSearch



procedure TFAutoSearch.Button1Click(Sender: TObject);
begin
  FileSearch(Edit1.Text, Edit2.Text, CheckBox1.State in [cbChecked]);
end;

end.
like image 274
Glen Morse Avatar asked Dec 26 '22 17:12

Glen Morse


1 Answers

The easiest way is to use ExtractFileExt against the current filename and check to see if it matches either of your desired extensions.

Here's a fully-rewritten version of your FileSearch routine which does exactly what you're trying to do (according to your question, anyway):

procedure TFAutoSearch.FileSearch(const ARoot: String);
var
  LExt, LRoot: String;
  LRec: TSearchRec;
begin
  LRoot := IncludeTrailingPathDelimiter(ARoot);
  if FindFirst(LRoot + '*.*', faAnyFile, LRec) = 0 then
  begin
    try
      repeat
        if (LRec.Attr and faDirectory <> 0) and (LRec.Name <> '.') and (LRec.Name <> '..') then
          FileSearch(LRoot + LRec.Name)
        else
        begin
          LExt := UpperCase(ExtractFileExt(LRoot + LRec.Name));
          if (LExt = '.CBR') or (LExt = '.CBZ') then
            ListBox1.Items.Add(LRoot + LRec.Name);
        end;
      until (FindNext(LRec) <> 0);
    finally
      FindClose(LRec);
    end;
  end;
end;

While the other answer suggesting the use of multiple extensions as a mask *.cbr;*.cbz should (in principal anyway) work, I've noted through bitter experience that the FindFirst and FindNext methods in Delphi tend not to accept multiple extensions in a mask!

The code I've provided should work just fine for your needs, so enjoy!

UPDATED: To allow the use of multiple extensions in a Mask dynamically at runtime (as indicated by the OP's first comment to this answer).

What we're going to do is take a String from your TEdit control (this String is one or more File Extensions as you would expect), "Explode" the String into an Array, and match each file against each Extension in the Array.

Sounds more complicated than it is:

type
  TStringArray = Array of String; // String Dynamic Array type...

// Now let's provide a "Mask Container" inside the containing class...
  TFAutoSearch = class(TForm)
    // Normal stuff in here
  private
    FMask: TStringArray; // Our "Mask Container"
  end;

This code will populate FMask with each individual mask extension separated by a ; such as .CBR;.CBZ.

Note this method will not accept Wildcard characters or any other Regex magic, but you can modify it as you require!

procedure TFAutoSearch.ExplodeMask(const AValue: String);
var
  LTempVal: String;
  I, LPos: Integer;
begin
  LTempVal := AValue;
  I := 0;
  while Length(LTempVal) > 0 do
  begin
    Inc(I);
    SetLength(FMask, I);
    LPos := Pos(';', LTempVal);

    if (LPos > 0) then
    begin
      FMask[I - 1] := UpperCase(Copy(LTempVal, 0, LPos - 1));
      LTempVal := Copy(LTempVal, LPos +  1, Length(LTempVal));
    end
    else
    begin
      FMask[I - 1] := UpperCase(LTempVal);
      LTempVal := EmptyStr;
    end;
  end;
end;

We now need a function to determine if the nominated file matches any of the defined Extensions:

function TFAutoSearch.MatchMask(const AFileName: String): Boolean;
var
  I: Integer;
  LExt: String;
begin
  Result := False;
  LExt := UpperCase(ExtractFileExt(LExt));
  for I := Low(FMask) to High(FMask) do
    if (LExt = FMask[I]) then
    begin
      Result := True;
      Break;
    end;
end;

Now here's the modified FileSearch procedure:

procedure TFAutoSearch.FileSearch(const ARoot: String);
var
  LRoot: String;
  LRec: TSearchRec;
begin
  LRoot := IncludeTrailingPathDelimiter(ARoot);
  if FindFirst(LRoot + '*.*', faAnyFile, LRec) = 0 then
  begin
    try
      repeat
        if (LRec.Attr and faDirectory <> 0) and (LRec.Name <> '.') and (LRec.Name <> '..') then
          FileSearch(LRoot + LRec.Name)
        else
        begin
          if (MatchMask(LRoot + LRec.Name)) then
            ListBox1.Items.Add(LRoot + LRec.Name);
        end;
      until (FindNext(LRec) <> 0);
    finally
      FindClose(LRec);
    end;
  end;
end;

Finally, here's how you initiate your search:

procedure TFAutoSearch.btnSearchClick(Sender: TObject);
begin
  ExplodeMask(edMask.Text);
  FileSearch(edPath.Text);
end;

Where edMask is defined in your question as Edit2 and edPath is defined in your question as Edit1. Just remember that this method doesn't support the use of Wildcard or other Special Chars, so edMask.Text should be something like .CBR;.CBZ

If you use the Regex library for Delphi, you could easily modify this method to support all of the Expression Cases you could ever imagine!

like image 155
LaKraven Avatar answered Jan 09 '23 16:01

LaKraven