Finder: căutarea fișierelor
Aveți nevoie să găsiți fișiere care corespund unei anumite măști? Finder vă va ajuta. Este un instrument versatil și rapid pentru parcurgerea structurii de directoare.
Instalare:
composer require nette/utils
Exemplele presupun că a fost creat un alias:
use Nette\Utils\Finder;
Utilizare
Mai întâi vom arăta cum puteți folosi Nette\Utils\Finder pentru a afișa numele fișierelor cu
extensiile .txt
și .md
în directorul curent:
foreach (Finder::findFiles(['*.txt', '*.md']) as $name => $file) {
echo $file;
}
Directorul implicit pentru căutare este directorul curent, dar îl puteți schimba folosind metodele in() sau from(). Variabila $file
este o instanță a clasei FileInfo cu o mulțime de metode utile. Cheia $name
conține calea către fișier sub
formă de șir.
Ce se caută?
Pe lângă metoda findFiles()
, există și findDirectories()
, care caută doar directoare, și
find()
, care le caută pe ambele. Aceste metode sunt statice, deci pot fi apelate fără a crea o instanță.
Parametrul cu masca este opțional; dacă nu îl specificați, se caută totul.
foreach (Finder::find() as $file) {
echo $file; // acum se vor afișa toate fișierele și directoarele
}
Cu ajutorul metodelor files()
și directories()
puteți specifica ce altceva să se caute. Metodele
pot fi apelate repetat, iar ca parametru se poate specifica și un array de măști:
Finder::findDirectories('vendor') // toate directoarele
->files(['*.php', '*.phpt']); // plus toate fișierele PHP
O alternativă la metodele statice este crearea unei instanțe folosind new Finder
(un obiect nou creat astfel nu
caută nimic) și specificarea a ceea ce se caută folosind files()
și directories()
:
(new Finder)
->directories() // toate directoarele
->files('*.php'); // plus toate fișierele PHP
În mască puteți folosi metacaracterele *
, **
, ?
și
[...]
. Puteți chiar specifica directoare, de exemplu src/*.php
va căuta toate fișierele PHP din
directorul src
.
Link-urile simbolice (symlinks) sunt, de asemenea, considerate directoare sau fișiere.
Unde se caută?
Directorul implicit pentru căutare este directorul curent. Îl puteți schimba folosind metodele in()
și
from()
. După cum sugerează numele metodelor, in()
caută doar în directorul specificat, în timp ce
from()
caută și în subdirectoarele sale (recursiv). Dacă doriți să căutați recursiv în directorul curent,
puteți folosi from('.')
.
Aceste metode pot fi apelate de mai multe ori sau li se pot transmite mai multe căi sub formă de array; fișierele vor fi
căutate apoi în toate directoarele specificate. Dacă unul dintre directoare nu există, se va arunca o excepție
Nette\UnexpectedValueException
.
Finder::findFiles('*.php')
->in(['src', 'tests']) // caută direct în src/ și tests/
->from('vendor'); // caută și în subdirectoarele vendor/
Căile relative sunt considerate relative la directorul curent. Desigur, se pot specifica și căi absolute:
Finder::findFiles('*.php')
->in('/var/www/html');
În cale se pot folosi metacaracterele *
, **
, ?
. De
exemplu, folosind calea src/*/*.php
puteți căuta toate fișierele PHP din directoarele de nivelul al doilea din
directorul src
. Caracterul **
, numit globstar, este un atu puternic, deoarece permite căutarea și în
subdirectoare: folosind src/**/tests/*.php
căutați toate fișierele PHP din directorul tests
aflat în
src
sau în oricare dintre subdirectoarele sale.
Pe de altă parte, metacaracterele [...]
nu sunt suportate în cale, adică nu au o semnificație specială,
pentru a evita comportamente nedorite în cazul în care căutați, de exemplu, in(__DIR__)
și, întâmplător, în
cale apar caracterele []
.
La căutarea fișierelor și directoarelor în adâncime, se returnează mai întâi directorul părinte și abia apoi
fișierele conținute în el, comportament ce poate fi inversat folosind childFirst()
.
Metacaractere
În mască puteți folosi mai multe caractere speciale:
*
– înlocuiește orice număr de caractere (cu excepția/
)**
– înlocuiește orice număr de caractere, inclusiv/
(adică se poate căuta pe mai multe niveluri)?
– înlocuiește un singur caracter (cu excepția/
)[a-z]
– înlocuiește un singur caracter din lista de caractere din parantezele drepte[!a-z]
– înlocuiește un singur caracter din afara listei de caractere din parantezele drepte
Exemple de utilizare:
img/?.png
– fișiere cu nume dintr-o singură literă, cum ar fi0.png
,1.png
,x.png
, etc.logs/[0-9][0-9][0-9][0-9]-[01][0-9]-[0-3][0-9].log
– loguri în formatulYYYY-MM-DD
src/**/tests/*
– fișiere în directorulsrc/tests
,src/foo/tests
,src/foo/bar/tests
și așa mai departe.docs/**.md
– toate fișierele cu extensia.md
din toate subdirectoarele directoruluidocs
Excludere
Cu ajutorul metodei exclude()
, puteți exclude fișiere și directoare din căutare. Specificați o mască
căreia fișierul nu trebuie să îi corespundă. Exemplu de căutare a fișierelor *.txt
, cu excepția celor care
conțin litera X
în nume:
Finder::findFiles('*.txt')
->exclude('*X*');
Pentru a omite parcurgerea anumitor subdirectoare, folosiți exclude()
:
Finder::findFiles('*.php')
->from($dir)
->exclude('temp', '.git');
Filtrare
Finder oferă mai multe metode pentru filtrarea rezultatelor (adică reducerea lor). Le puteți combina și apela repetat.
Cu ajutorul size()
, filtrăm după dimensiunea fișierului. Astfel, găsim fișiere cu dimensiunea în intervalul
100 – 200 de octeți:
Finder::findFiles('*.php')
->size('>=', 100)
->size('<=', 200);
Metoda date()
filtrează după data ultimei modificări a fișierului. Valorile pot fi absolute sau relative la
data și ora curentă; de exemplu, astfel găsim fișiere modificate în ultimele două săptămâni:
Finder::findFiles('*.php')
->date('>', '-2 weeks')
->from($dir);
Ambele funcții înțeleg operatorii >
, >=
, <
, <=
,
=
, !=
, <>
.
Finder permite, de asemenea, filtrarea rezultatelor folosind funcții personalizate. Funcția primește ca parametru obiectul
Nette\Utils\FileInfo
și trebuie să returneze true
pentru ca fișierul să fie inclus în
rezultate.
Exemplu: căutarea fișierelor PHP care conțin șirul Nette
(indiferent de majuscule/minuscule):
Finder::findFiles('*.php')
->filter(fn($file) => strcasecmp($file->read(), 'Nette') === 0);
Filtrare în adâncime
La căutarea recursivă, puteți seta adâncimea maximă de parcurgere folosind metoda limitDepth()
. Dacă setați
limitDepth(1)
, se parcurg doar primele subdirectoare; limitDepth(0)
dezactivează parcurgerea în
adâncime, iar valoarea –1 anulează limita.
Finder permite, folosind funcții personalizate, să decideți în ce director să se intre la parcurgere. Funcția primește
ca parametru obiectul Nette\Utils\FileInfo
reprezentând directorul și trebuie să returneze true
pentru a intra în acel director:
Finder::findFiles('*.php')
->descentFilter(fn($file) => $file->getBasename() !== 'temp');
Sortare
Finder oferă, de asemenea, mai multe funcții pentru sortarea rezultatelor.
Metoda sortByName()
sortează rezultatele după numele fișierelor. Sortarea este naturală, adică gestionează
corect numerele din nume și returnează, de exemplu, foo1.txt
înainte de foo10.txt
.
Finder permite, de asemenea, sortarea folosind o funcție personalizată. Aceasta primește ca parametru două obiecte
Nette\Utils\FileInfo
și trebuie să returneze rezultatul comparației folosind operatorul spaceship
<=>
(adică -1
, 0
sau 1
). De exemplu, astfel sortăm fișierele după
dimensiune:
$finder->sortBy(fn($a, $b) => $a->getSize() <=> $b->getSize());
Mai multe căutări diferite
Dacă aveți nevoie să găsiți mai multe fișiere diferite în locații diferite sau care îndeplinesc alte criterii,
utilizați metoda append()
. Aceasta returnează un nou obiect Finder
, permițând înlănțuirea
apelurilor de metode:
($finder = new Finder) // salvăm primul Finder în variabila $finder!
->files('*.php') // în src/ căutăm fișiere *.php
->from('src')
->append()
->files('*.md') // în docs/ căutăm fișiere *.md
->from('docs')
->append()
->files('*.json'); // în directorul curent căutăm fișiere *.json
Alternativ, metoda append()
poate fi folosită pentru a adăuga un fișier specific (sau un array de fișiere).
În acest caz, returnează același obiect Finder
:
$finder = Finder::findFiles('*.txt')
->append(__FILE__);
FileInfo
Nette\Utils\FileInfo este o clasă care reprezintă un fișier sau un director în rezultatele căutării. Este o extensie a clasei SplFileInfo, care oferă informații precum dimensiunea fișierului, data ultimei modificări, numele, calea etc.
În plus, oferă metode pentru returnarea căii relative, ceea ce este util la parcurgerea în adâncime:
foreach (Finder::findFiles('*.jpg')->from('.') as $file) {
$absoluteFilePath = $file->getRealPath();
$relativeFilePath = $file->getRelativePathname();
}
De asemenea, aveți la dispoziție metode pentru citirea și scrierea conținutului fișierului:
foreach ($finder as $file) {
$contents = $file->read();
// ...
$file->write($contents);
}
Returnarea rezultatelor ca array
După cum s-a văzut în exemple, Finder implementează interfața IteratorAggregate
, astfel încât puteți
folosi foreach
pentru a parcurge rezultatele. Este implementat astfel încât rezultatele sunt încărcate doar pe
parcursul iterării, deci dacă aveți un număr mare de fișiere, nu se așteaptă până când toate sunt citite.
Rezultatele pot fi, de asemenea, returnate ca un array de obiecte Nette\Utils\FileInfo
, folosind metoda
collect()
. Array-ul nu este asociativ, ci indexat numeric.
$array = $finder->findFiles('*.php')->collect();