Newsgroup: it.comp.lang.delphi
Titolo: FindFirst & FindClose ?!?

Ciao a tutti seguo spesso(leggo) il NG, ma nn ho trovato una risposta al mio
quesito. Volevo chiedervi una cosa
ho un Hd dove tengo parecchie directory con relativi file all'interno.
Capita ke in una directory ve ne siano altre, sottodirectory. Allora volevo
catalogarle in un file di testo. Allora volevo creare un eseguibile con
delphi che mi faccia un elenco dei file nelle relative directory, ho provato
con FindFirst, FindResult, ma riesco solo a fargli leggere la I directory,
vi posto il codice..
****************************************
Var F : TSearchRec;
    FindResult : integer;
begin
  FindResult :=  FindFirst('c:\'+'\*.*',faDirectory,F);
  while FindResult=0 do
  begin
          Memo1.Lines.Add(PathSource+'\'+F.Name);
          FindResult :=  FindNext(F);
  end;
  FindClose(F);
end;
****************************************
Il risultato nel TMemo è C:\autoexec.bat, C:\config.sys, solo i file nella
root principale, ma nn mi mostra ad esempio C:\Windows\winmine.exe
Spero di essere stato chiaro.
            Grazie e Ciao
                                Frunktz

vedi l'esempio della virtual listview.
Trovi un esempio di utilizzo della interfaccia IShellqualcosaltro.
In pratica, usi cio che usa la gestione risorse per leggere files e
cartelle.
Bye
A.

 con FindFirst, FindResult, ma riesco solo a fargli leggere la I directory,
FindFirst e FindNext non sono recursive. Esse cercano solamente nella
cartella che gli passi. Per far sě che cerchino anche nelle subdirectory
puoi implementare una banale ricursione.
Ciao
Matteo

 volevo catalogarle in un file di testo. 
qui di seguito ti posto il codice di una classe che ho scritto e che fa 
proprio ciò che tu richiedi. 
Dopo averla costruita col solito modo, gli passi il percorso di una 
cartella nella proprietà Path e lei ti restituisce nella proprietà DirNames 
l'elenco completo di tutte le cartelle/sottocartelle/sotto-sottocartelle 
ecc... (in FileNames i nomi di tutti i files).
-------(INIZIO CODICE)-------
unit ExpandedFolder;
(***********************************************************)
(*    by Mauro Falzari (
open....@email.it
), AGO 2002
(*    [tested on Win98SE, please report bugs to my email, tnx]
(***********************************************************)
interface
uses
  Classes;
type
  TExpandedFolder = class
  private
    FDirNames, FFileNames: TStringList;
    FPath: string;
    FDepth, FMaxDepth: Shortint;
    FCancel: Boolean;
    procedure Get;
    procedure SetPath(const Value: string);
    procedure SetMaxDepth(const Value: Shortint);
    function GetDirNames: TStringList;
    function GetFileNames: TStringList;
  public
    constructor Create;
    destructor Destroy; override;
    procedure Cancel;
    { serve per cancellare la ricerca in corso, nel caso di operazioni
      troppo lunghe }
    property Path: string read FPath write SetPath;
    { percorso della cartella corrente}
    property MaxDepth: Shortint read FMaxDepth write SetMaxDepth;
    { profondità di ispezione delle sottocartelle:
      se -1 equivale al massimo livello raggiungibile, cioè verrà
        restituito un elenco contenente TUTTI i files contenuti
        in TUTTE le sottocartelle e un elenco contenente i nomi
        di TUTTE le sottocartelle esistenti
      se 0 verrà ispezionata solo la cartella corrente, cioè verrà
        restituito un elenco contenente i files contenuti
        nella sola cartella corrente e un elenco delle cartelle
        contenute nella sola cartella corrente
      se > 0 il controllo verrà fatto fino al livello dato}
    property DirNames: TStringList read GetDirNames;
    { lista dei nomi delle sottocartelle }
    property FileNames: TStringList read GetFileNames;
    { lista dei nomi dei file contenuti E nella cartella corrente
      E nelle sottocartelle }
  end;
implementation
uses
  Windows, SysUtils, Forms;
const
  NO_MAX_DEPTH: Shortint = -1;
    //non c'è limite alla profondità di ricerca
{ TExpandedFolder }
constructor TExpandedFolder.Create;
begin
  FDirNames:= TStringList.Create;
  FFileNames:= TStringList.Create;
  FMaxDepth:= NO_MAX_DEPTH;
end;
destructor TExpandedFolder.Destroy;
begin
  FDirNames.Free;
  FFileNames.Free;
end;
procedure TExpandedFolder.Cancel;
begin
  FCancel:= True;
end;
{  originale
procedure TExpandedFolder.Get;
var
  s: TSearchRec;
  NameComplete: string;
  ASubFolder: TExpandedFolder;
const
  FIND_ALL_FILES = '\*.*';
  FIND_RESULT_OK = 0;
begin
  FDirNames.Clear;
  FFileNames.Clear;
  FCancel:= False;
  try
    if FindFirst(ExcludeTrailingPathDelimiter(FPath) +
      FIND_ALL_FILES, faAnyFile, s) = FIND_RESULT_OK
    then
      repeat
        Application.ProcessMessages;
        if FCancel then Exit;
        NameComplete:= IncludeTrailingPathDelimiter(FPath) + s.Name;
        if not IsDotPath(s.Name) then
          if IsDirectory(NameComplete) then          //è una dir
            begin
              FDirNames.Add(NameComplete);
              ASubFolder:= TExpandedFolder.Create;
              try
                Inc(FDepth, ASubFolder.FDepth);
                if (FMaxDepth = NO_MAX_DEPTH)
                  or (FDepth < FMaxDepth)
                then
                begin
                  Application.ProcessMessages;
                  if FCancel then Exit;
                  ASubFolder.FDepth:= FDepth + 1;
                  ASubFolder.MaxDepth:= FMaxDepth;
                  ASubFolder.Path:= NameComplete;
                  FDirNames.AddStrings(ASubFolder.DirNames);
                  FFileNames.AddStrings(ASubFolder.FileNames);
                end
              finally
                ASubFolder.Free;
              end //try
            end
          else
            FFileNames.Add(NameComplete);
      until FindNext(s) <> FIND_RESULT_OK;
  finally
    FindClose(s);
  end;
end; }
function IsDotName(const FileName: string): Boolean;
{ rileva se il nome del file è '.' o '..'
  In DOS il nome di file '.' equivale alla directory corrente,
  mentre il nome '..' alla directory immediatamente superiore.
  Qui è sufficiente eseguire un controllo solo sull'ultimo
  carattere se è uguale a '.', perchè il DOS (Win98SE) non permette
  nomi di file terminanti con uno o più punti, che vengono troncati
  automaticamente (es: 'AFILE...' diventa 'AFILE'}
begin
  Result:= FileName[Length(FileName)] = '.';
end;
function IsDirectory(const FileName: string): Boolean;
const
{ questi valori vengono usati dal programma "Microangelo" per
  mostrare le cartelle con icone differenti da quelle predefinite
  (Win98SE)}
  MICROANGELO_FOLDER_SYS  =   17;
  MICROANGELO_FOLDER_CUST =   20;
begin
  Result:= (GetFileAttributes(PChar(FileName)) in
    [faDirectory, MICROANGELO_FOLDER_CUST, MICROANGELO_FOLDER_SYS]);
end;
procedure TExpandedFolder.Get;
var
  s: TSearchRec;
  NameComplete: string;
  ASubFolder: TExpandedFolder;
const
  FIND_ALL_FILES  =   '\*.*';
  FIND_RESULT_OK  =   0;
begin
  FDirNames.Clear;
  FFileNames.Clear;
  FCancel:= False;
  try
    if FindFirst(ExcludeTrailingPathDelimiter(FPath) +
      FIND_ALL_FILES, faAnyFile, s) = FIND_RESULT_OK
    then
      repeat
        Application.ProcessMessages;    //permette d'intercettare
//per esempio la pressione di un tasto collegato col metodo Cancel
        if FCancel then Exit;           //vedi metodo Cancel
        NameComplete:= IncludeTrailingPathDelimiter(FPath) + s.Name;
        if not IsDotName(s.Name) then
          if IsDirectory(NameComplete) then
            begin
              FDirNames.Add(NameComplete);
              ASubFolder:= TExpandedFolder.Create;
              try
                Inc(FDepth, ASubFolder.FDepth);
                if (FMaxDepth = NO_MAX_DEPTH)
                  or (FDepth < FMaxDepth)
                then
                begin
                  Application.ProcessMessages;
                  if FCancel then Exit;   //vedi metodo Cancel
                  ASubFolder.FDepth:= FDepth + 1;
                  ASubFolder.MaxDepth:= FMaxDepth;
                  ASubFolder.Path:= NameComplete;
                  FDirNames.AddStrings(ASubFolder.DirNames);
                  FFileNames.AddStrings(ASubFolder.FileNames)
                end
              finally
                ASubFolder.Free
              end           //try
            end
          else              //nel caso si tratti di un file
            FFileNames.Add(NameComplete)
      until FindNext(s) <> FIND_RESULT_OK
  finally
    FindClose(s)
  end
end;
procedure TExpandedFolder.SetPath(const Value: string);
begin
  if (Trim(Value) <> EmptyStr) and
    (UpperCase(Trim(Value)) <> FPath)
  then
  begin
    FPath:= UpperCase(Trim(Value));
    Get;
  end
end;
procedure TExpandedFolder.SetMaxDepth(const Value: Shortint);
begin
  if Value <> FMaxDepth then
  begin
    if Value < NO_MAX_DEPTH then
      FMaxDepth := NO_MAX_DEPTH
    else
      FMaxDepth:= Value;
    if FPath <> EmptyStr then
      Get;
  end
end;
function TExpandedFolder.GetFileNames: TStringList;
begin
  FFileNames.Sort;
  Result:= FFileNames;
end;
function TExpandedFolder.GetDirNames: TStringList;
begin
  FDirNames.Sort;
  Result:= FDirNames;
end;
end.
--------(FINE CODICE)------------
-- 
Mauro Falzari.
"Se guardi nell'abisso, anche l'abisso guarda in te."
(Friedrich Nietzsche)

1. Grazie per la risposta.
2. Ho guardato l'esempio di Delphi, ma nn riesco a venirne a capo, a me
serve l'elenco delle directory(e subdirectory), con i relativi file inclusi
all'interno di esse, come posso risolvere, nel codice nn sono riuscito a
trovare quello ke mi serviva..., nell'help, ho provato a cercare, senza aver
trovato niente
3. Puoi darmi uno spunto?
        Grazie ancora Frunktz

Scusa se ti chiedo ancora una cosa, ma come faccio ad implementarlo nel mio
programma, includo la unit, e poi come faccio a crearla. Scusa la domanda
banale ma nn ho mai lavorato con le classi... E' da poco che mi sono
avvicinato a Delphi, cmq faccio esperimenti poi ti so dire. PS:- Grazie
ancora per le risposte. Ciao Frunktz

 programma, includo la unit, e poi come faccio a crearla. 
siccome un esempio vale più di mille parole, ti suggerisco di creare una 
nuova applicazione, mettere una ListBox sulla form e collegare il seguente 
codice:
implementation
uses
  ExpandedFolder;
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
  with TExpandedFolder.Create do
  try
    Path:= ExtractFilePath(Application.ExeName);
    ListBox1.Items:= FileNames;
  finally
    Free
  end
end;
end.


Uhm vedi il problema è un altro. Adesso o sbaglio io o cosa. Quando compilo
la tua unit, mi da errore nella procedura GET, dicendomi che nn trova la
variabile o cosa ExcludeTrailingPathDelimiter e
IncludeTrailingPathDelimiter. Allora x farla compilare le ho eliminate. Ora
per farla funzionare l'ho fatto ma
1. nn mi fa vedere i file delle altre subdirectory all'interno della stessa
directory
2. Se metto DirNames, nn mi fa vedere niente.
3. Quando chiudo l'applicazione mi fa un errore di access violation...
Forse sbaglio da qualche parte ma nn riesco a farlo funzionare.
    Soluzioni???            Grazie e Ciao Frunktz

 IncludeTrailingPathDelimiter. 
da ciň deduco che hai una versione precedente a Delphi6, quindi sostituisci 
ExcludeTrailingPathDelimiter con ExcludeTrailingBackslash e 
IncludeTrailingPathDelimiter con IncludeTrailingBackslash.


ho apprezzato la tua unit  ExpandedFolder
anche come esempio di creazione di una classe ed uso delle property  ( ne
avevo bisogno )
E' ottimizzabile?
Anche escludendo il sorting delle cartelle ed il controllo
sulla profondità del percorso ( che tra l'altro incidono in maniera
trascurabile sulle prestazioni ) i tempi di esecuzione rimangono alti (
almeno il doppio dell'utilità di window  "trova file" )
forse l'utilità di window è scritta in assembler?
Saluti

 E' ottimizzabile?
sicuramente: nel metodo Get ho utilizzato la ricorsione (creo una nuova 
istanza di TExpandedFolder per ogni sottocartella che incontro) per 
imparare/mettere in pratica appunto quella tecnica e per lavorare con un 
codice semplice e (spero) leggibile, ma ciò comporta un grande spreco di 
risorse e certamente un rallentamento delle prestazioni.
Credo che un buon modo per ottenere un incremento delle prestazioni sia 
riscrivere il metodo Get in assembler (utilizzando anche delle chiamate a 
int 21h) SENZA usare la ricorsione.
Tanto per farti un esempio, guarda sulla guida dell'SDK -inclusa in D6- 
l'argomento "Interrupt 21h Function 714Fh".


Se vuoi c'è un componente gratuito che ti fa da solo tutti i find-first
find-next
comprese le sotto directory dandoti la lista sia dei file che delle
directory.
Inoltre ti permette tramite degli eventi di fare delle operazioni per ogni
file o directory
trovata.
L'indirizzo è questo:
http://ramaya.azpoint.net/prodotto.asp?ID=3

Grazie mille a tutti in effetti ho la versione 5 di Delphi, grazie ora provo
e ti o vi faccio sapere. Grazie ancora