jak policzyć pliki w katalogu i jego podkatalogach?

0

w necie wykopałem coś takiego ale nie działa?


//Funkcja liczy ile jest plików w podanym katalogu i jego podkatalogach.
function Policz_Pliki(RozpocznijOd:String; Maska:String;Licz_W_Podkatalogach:Boolean):int64;
var
T:   TSearchRec;
sPom:     string;
sPath:    string;
Liczba_plikow: int64;
begin
     try
          Liczba_plikow:=0;
          sPath:=ExtractFileDir(RozpocznijOd)+'\';
          FindFirst(sPath+Maska, faAnyFile, T);
          repeat
              if (T.Attr <> faDirectory) and
                  (T.Attr <> faVolumeID) and
                   (T.Attr <> faSymLink) and
                     (T.Attr <>  faAnyFile) then
              begin
                   Liczba_plikow:=Liczba_plikow+1;
              end;

              if T.Attr = faDirectory then
              begin // no to jest katalog
                   if Licz_W_Podkatalogach then
                   begin
                        sPom:='';
                        sPom:=sPath+T.Name;
                        Policz_Pliki(sPom, Maska, True);
                   end;
              end;
          until FindNext(T) <> 0;
          FindClose(T);
     except
          Result:=0;
     end;
     Result:=Liczba_plikow;
end;
0

Nie sprecyzowałeś co nie działa, nie zlicza, źle zlicza czy nie kompiluje się i jaki błąd. I jak tutaj się później dziwić opryskliwym odpowiedziom @-123 skoro dostajemy taką "wiele mówiącą informację" w stylu "nie działa" i tymbardziej smutne że dostajemy ją po raz 97834324 i to jeszcze od osoby, która jakiś czas jest już na tym forum. Anyway, co do wyszukiwania plików, również w podkatalogach polecam poniższy kod. Dzięki procedurze podanej w parametrze FileSearchOnFindProc otrzymujesz wynik gdy znaleziono. Dlatego nie problem wtedy zadeklarować na poczatku zmienną globalną, dla pewności przed wyszukaniem ją wyzerować, a w owej procedurze zwiększąć o jeden. Na koncu po wykonaniu procedury FileSearch można pokazać wynik w zmiennej globalnej. A w razie potrzeb możesz ten kod sobie przerobić tak aby działał wedle potrzeb. No i oczywiście kod pisany w WinAPI także do szczęścia potrzebuje tylko modułu Windows dodanego do sekcji uses i "nie tuczy" on zbytnio wynikowego exeka, jeżeli napiszemy program oczywiście w WinAPI. Zastosowanie procedur do pokazywania wyników oraz postępu - powoduje, że nie trzeba stosować tablic dynamicznych w celu zebrania wyników, bo można je od razu dodawać na przykład do jakiś kontrolek wizualnych jak na przykład ListBox utworzony w oknie dialogowym z zasobów.

//..
type
  TFileSearchOnFindProc = procedure(FoundFileName : string);
  TFileSearchProgressProc = procedure(CurrentSearchPath : string);

//...

function AddBackSlash(Path : string) : string;
begin
  Result := '';
  if Path <> '' then
  begin
    if Path[Length(Path)] <> '\' then
    begin
      Result := Path + '\'
    end
    else
    begin
      Result := Path;
    end;
  end;
end;

procedure FileSearch(const PathName, FileName : string; const InDir : boolean;
  FileSearchOnFindProc : TFileSearchOnFindProc; FileSearchProgressProc : TFileSearchProgressProc);
var
  H : THandle;
  Path : string;
  WFD : TWIN32FindData;
begin
  Path := AddBackSlash(PathName);
  if @FileSearchProgressProc <> nil then
  begin
    FileSearchProgressProc(Path);
  end;
  H := Windows.FindFirstFile(PChar(Path + FileName), WFD);
  if H <> INVALID_HANDLE_VALUE then
  begin
    try
      repeat
        if (WFD.dwFileAttributes and FILE_ATTRIBUTE_ARCHIVE = FILE_ATTRIBUTE_ARCHIVE)
          or (WFD.dwFileAttributes and FILE_ATTRIBUTE_NORMAL = FILE_ATTRIBUTE_NORMAL) then
        begin
          if @FileSearchOnFindProc <> nil then
          begin
            FileSearchOnFindProc(Path + WFD.cFileName);
          end;
        end;
      until not FindNextFile(H, WFD);
    finally
      Windows.FindClose(H);
    end;
  end;
  if InDir then
  begin
    H := Windows.FindFirstFile(PChar(Path + '*.*'), WFD);
    if H <> INVALID_HANDLE_VALUE then
    begin
      try
        repeat
          if (WFD.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY = FILE_ATTRIBUTE_DIRECTORY)
            and (Copy(WFD.cFileName, 1, 1) <> '.') and (WFD.cFileName <> '..') then
          begin
            FileSearch(Path + WFD.cFileName, FileName, True, FileSearchOnFindProc, FileSearchProgressProc);
          end;
        until not FindNextFile(H, WFD);
      finally
        Windows.FindClose(H);
      end;
    end;
  end;
end;
//...
0

Dlaczego nie działa bo funkcja ta nie potrafi prawidłowo oddzielić pliku od innych danych odpytywanych ze struktury a jej dodatkowym problemem jest interpretacja dojścia do udziału sieciowego. Jest mi potrzebna tylko ilość plików jaka znajduje się w podanym katalogi i jego podkatalogach i szukam prostej funkcji ,która to realizuje.

0
tester_68k napisał(a):

bo funkcja ta nie potrafi prawidłowo oddzielić pliku od innych danych odpytywanych ze struktury

if (T.Attr <> faDirectory) and
(T.Attr <> faVolumeID) and
(T.Attr <> faSymLink) and
(T.Attr <>  faAnyFile) then

Trzeba myśleć a nie bezkrytycznie ściągać z neta.
@olesio pokazał jak należy testować atrybuty.

1

Olesio, znowu mnie wyprzedziłeś ;P

function Policz_Pliki(RozpocznijOd,Maska:String;Licz_W_Podkatalogach:Boolean):int64;
var T:TSearchRec;
var Ret:Integer;
begin
WriteLn(RozpocznijOd);
  Result:=0;
  try
    Ret:=FindFirst(RozpocznijOd+Maska,faAnyFile,T);
    while Ret=0 do
    begin
      if (T.Attr and (faDirectory or faVolumeId))=0 then
      begin
        Inc(Result);
      end;
      Ret:=FindNext(T);
    end;
    FindClose(T);
    if Licz_W_Podkatalogach then
    begin
      Ret:=FindFirst(RozpocznijOd+'*.*',faDirectory,T);
      while Ret=0 do
      begin
        if (T.Attr=faDirectory)and(T.Name<>'.')and(T.Name<>'..') then
        begin
          Inc(Result,Policz_Pliki(RozpocznijOd+T.Name+'\',Maska,Licz_W_Podkatalogach));
        end;
        Ret:=FindNext(T);
      end;
      FindClose(T);
    end;
  except
  end;
end;
0

Nie chcę Was załamywać, ale to da się zrobić z linii poleceń pod Linuksem w jednej linijce...
find sciezka_do_katalogu -type f | wc -l
Nie wiem jak by to wyglądało z użyciem Windowsiarskiego terminala, ale może też dałoby radę zrobić coś podobnego ;)

Sorry za offtop, jakby się to moderatorowi miało nie spodobać.

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0