viernes, 8 de noviembre de 2019

Obtener los archivos de una carpeta con GetFilesInDir

GetFilesInDir es un procedimiento de clase que la clase TShellTreeView hereda de la clase TCustomShellTreeView.
TShellTreeView es un componente que se encuentra en la paleta Misc de Lazarus y que ha quedado estancado por el tema de la compatibilidad con versiones anteriores o retrocompatibilidad. No obstante es muy útil y lo veremos más en profundidad en otra entrada.
Vale esta aclaración, porque el procedimiento en cuestión, tiene una fuga de memoria que no se corrige ni se corregirá, según lo leído en un hilo del foro oficial de Lazarus y Free Pascal, justamente para mantener la compatibilidad, es decir, para solucionarlo habría que hacer cambios que afectarían la compatibilidad con versiones anteriores, es decir, con programas viejos o no tanto, que necesitan compilarse con la versión más reciente de FPC.
Lo bueno es que con una línea de código se soluciona el problemita del memory leaks.

Otra forma de obtener los archivos de un directorio es mediante FindFirst, FindNext y FindClose.

Este sencillo ejemplo consta de tres componentes, un TShellTreeView, un TMemo y un TBitBtn.
unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ShellCtrls,
  StdCtrls, Buttons;

type

{ TForm1 }

TForm1 = class(TForm)
  BitBtn1: TBitBtn;
  Memo1: TMemo;
  ShellTreeView1: TShellTreeView;
  procedure BitBtn1Click(Sender: TObject);
private

public

end;

var
Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.BitBtn1Click(Sender: TObject);
var
  sl:TStringList;
begin
  Memo1.Clear;
  sl:=TStringList.Create;
  sl.OwnsObjects:=True; //evita memory leaks
  ShellTreeView1.GetFilesInDir(ShellTreeView1.Path,'*.*',[otNonFolders],sl,fstAlphabet);
  Memo1.Text:=sl.Text;
  FreeAndNil(sl);
end;

end.


Veamos el código fuente del procedimiento:

class procedure TCustomShellTreeView.GetFilesInDir(const ABaseDir: string;
AMask: string; AObjectTypes: TObjectTypes; AResult: TStrings; AFileSortType: TFileSortType);


Como vemos le pasamos varios parámetros, el primero el directorio en el cual debe buscar archivos, luego qué archivos (en este ejemplo simplemente *.* para todos los archivos), AObjectTypes es un conjunto de enumerados:

TObjectType = (otFolders, otNonFolders, otHidden);

TObjectTypes = set of TObjectType;


en este caso pedimos solo archivos que no sean carpetas, por lo tanto, archivos ocultos y carpetas no formarán parte del resultado. Nota: en Linux todo son archivos, también las carpetas.
El cuarto parámetro AResult: ahí le pasamos el TStringList, al cual antes de mandarlo, le establecimos la propiedad OwnObjects en True para el tema de evitar la fuga de memoria.
El último parámetro es un enumerado:

TFileSortType = (fstNone, fstAlphabet, fstFoldersFirst);

y se utiliza para indicar el orden de los archivos.
Para finalizar, se libera el TStringList.