Finder: Căutare fișiere

Aveți nevoie să găsiți fișiere care se potrivesc cu o anumită mască? Finder vă poate ajuta. Este un instrument versatil și rapid de navigare în structura directoarelor.

Instalare:

composer require nette/utils

Exemplele presupun că a fost creat un alias:

use Nette\Utils\Finder;

Utilizarea

În primul rând, să vedem cum puteți utiliza Nette\Utils\Finder pentru a lista numele fișierelor cu extensiile .txt și .md din 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 forma unui șir de caractere.

Ce trebuie să căutați?

Pe lângă metoda findFiles(), există și findDirectories(), care caută numai în directoare, și find(), care caută în ambele. Aceste metode sunt statice, deci pot fi apelate fără a crea o instanță. Parametrul mască este opțional, dacă nu îl specificați, se caută totul.

foreach (Finder::find() as $file) {
	echo $file; // acum sunt listate toate fișierele și directoarele
}

Utilizați metodele files() și directories() pentru a adăuga ce altceva trebuie căutat. Metodele pot fi apelate în mod repetat, iar ca parametru poate fi furnizată o matrice de măști:

Finder::findDirectories('vendor') // toate directoarele
	->files(['*.php', '*.phpt']); // plus toate fișierele PHP

O alternativă la metodele statice este de a crea o instanță folosind new Finder (obiectul nou creat în acest mod nu caută nimic) și de a specifica ce să caute folosind files() și directories():

(new Finder)
	->directories()      // toate directoarele
	->files('*.php');    // plus toate fișierele PHP

Puteți utiliza caractere wildcards *, **, ? and [...] în mască. Puteți specifica chiar și în directoare, de exemplu src/*.php va căuta toate fișierele PHP din directorul src.

Legăturile simbolice sunt considerate, de asemenea, directoare sau fișiere.

Directorul de căutare implicit este directorul curent. Puteți schimba acest lucru utilizând metodele in() și from(). După cum puteți vedea din numele metodelor, in() caută numai în directorul curent, în timp ce from() caută și în subdirectoarele acestuia (recursiv). Dacă doriți să căutați recursiv în directorul curent, puteți utiliza from('.').

Aceste metode pot fi apelate de mai multe ori sau le puteți transmite mai multe căi de acces sub formă de matrice, după care fișierele vor fi căutate în toate directoarele. În cazul în care unul dintre directoare nu există, se trimite un mesaj Nette\UnexpectedValueException.

Finder::findFiles('*.php')
	->in(['src', 'tests']) // caută direct în src/ și tests/
	->from('vendor');      // caută, de asemenea, în subdirectoarele vendor/

Căile relative sunt relative la directorul curent. Desigur, pot fi specificate și căi absolute:

Finder::findFiles('*.php')
	->in('/var/www/html');

Wildcards wildcards wildcards *, **, ? can be used in the path. For example, you can use the path src/*/*.php pentru a căuta toate fișierele PHP din directoarele de al doilea nivel din directorul src. Caracterul **, numit globstar, este un atu puternic, deoarece vă permite să căutați și în subdirectoare: utilizați src/**/tests/*.php pentru a căuta toate fișierele PHP din directorul tests aflate în src sau în oricare dintre subdirectoarele acestuia.

Pe de altă parte, caracterele wildcard [...] nu sunt acceptate în calea de acces, adică nu au o semnificație specială pentru a evita un comportament nedorit în cazul în care căutați, de exemplu, in(__DIR__) și, din întâmplare, în calea de acces apar caracterele [].

La căutarea în profunzime a fișierelor și directoarelor, este returnat mai întâi directorul părinte și apoi fișierele conținute în acesta, ceea ce poate fi inversat cu childFirst().

Caractere wildcard

Puteți utiliza mai multe caractere speciale în mască:

  • * – replaces any number of arbitrary characters (except /)
  • ** – înlocuiește orice număr de caractere arbitrare, inclusiv / (adică poate fi căutat pe mai multe niveluri)
  • ? – replaces one arbitrary character (except /)
  • [a-z] – înlocuiește un caracter din lista de caractere din parantezele pătrate
  • [!a-z] – înlocuiește un caracter din afara listei de caractere din parantezele pătrate

Exemple de utilizare:

  • img/?.png – fișiere cu numele cu o singură literă 0.png, 1.png, x.png, etc.
  • logs/[0-9][0-9][0-9][0-9]-[01][0-9]-[0-3][0-9].log – fișiere jurnal în format YYYY-MM-DD
  • src/**/tests/* – fișiere din directorul src/tests, src/foo/tests, src/foo/bar/tests și așa mai departe.
  • docs/**.md – toate fișierele cu extensia .md din toate subdirectoarele din directorul docs

Cu excepția

Utilizați metoda exclude() pentru a exclude fișierele și directoarele din căutări. Specificați o mască la care fișierul nu trebuie să 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*');

Utilizați exclude() pentru a sări peste subdirectoarele parcurse:

Finder::findFiles('*.php')
	->from($dir)
	->exclude('temp', '.git')

Filtrarea

Finder oferă mai multe metode de filtrare a rezultatelor (adică de reducere a acestora). Puteți să le combinați și să le apelați în mod repetat.

Utilizați size() pentru a filtra în funcție de dimensiunea fișierului. În acest fel, găsim fișiere cu dimensiuni între 100 și 200 de octeți:

Finder::findFiles('*.php')
	->size('>=', 100)
	->size('<=', 200);

Metoda date() filtrează în funcție de data la care fișierul a fost modificat ultima dată. Valorile pot fi absolute sau relative la data și ora curentă, de exemplu, în acest fel se pot găsi 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 vă permite, de asemenea, să filtrați rezultatele folosind funcții personalizate. Funcția primește ca parametru un obiect Nette\Utils\FileInfo și trebuie să returneze true pentru a include fișierul în rezultate.

Exemplu: Căutați fișierele PHP care conțin șirul Nette (fără a ține cont de majuscule și minuscule):

Finder::findFiles('*.php')
	->filter(fn($file) => strcasecmp($file->read(), 'Nette') === 0);

Filtrarea în profunzime

Atunci când efectuați o căutare recursivă, puteți seta adâncimea maximă de căutare utilizând metoda limitDepth(). Dacă setați limitDepth(1), sunt cercetate numai primele subdirectoare, limitDepth(0) dezactivează cercetarea în profunzime, iar o valoare de –1 anulează limita.

Finder vă permite să utilizați propriile funcții pentru a decide în ce director să intrați atunci când navigați. Funcția primește ca parametru un obiect Nette\Utils\FileInfo și trebuie să returneze true pentru a intra în directorul respectiv:

Finder::findFiles('*.php')
	->descentFilter($file->getBasename() !== 'temp');

Sortare

Finder oferă, de asemenea, mai multe funcții de sortare a rezultatelor.

Metoda sortByName() sortează rezultatele în funcție de numele fișierului. Sortarea este naturală, adică gestionează corect numerele din nume și returnează, de exemplu, foo1.txt înainte de foo10.txt.

Finder vă permite, de asemenea, să sortați utilizând o funcție personalizată. Aceasta primește ca parametri două obiecte Nette\Utils\FileInfo și trebuie să returneze rezultatul comparației cu operatorul <=>, de exemplu -1, 0 nebo 1. De exemplu, iată cum sortăm fișierele în funcție de 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 criterii diferite, utilizați metoda append(). Aceasta returnează un nou obiect Finder, astfel încât să puteți apela metodele în lanț:

($finder = new Finder) // stochează primul Finder în variabila $finder!
	->files('*.php')   // caută fișiere *.php în src/
	->from('src')
	->append()
	->files('*.md')    // în docs/ caută fișiere *.md
	->from('docs')
	->append()
	->files('*.json'); // în folderul curent caută fișiere *.json

Alternativ, puteți utiliza metoda append() pentru a adăuga un anumit fișier (sau o matrice de fișiere). În acest caz, se 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 de acces etc.

În plus, oferă metode pentru returnarea căilor relative, ceea ce este util atunci când se efectuează o căutare în profunzime:

foreach (Finder::findFiles('*.jpg')->from('.') as $file) {
	$absoluteFilePath = $file->getRealPath();
	$relativeFilePath = $file->getRelativePathname();
}

De asemenea, există metode de citire și scriere a conținutului unui fișier:

foreach ($finder as $file) {
    $contents = $file->read();
    // ...
    $file->write($contents);
}

Returnarea rezultatelor sub forma unui tablou

După cum s-a văzut în exemple, Finder implementează interfața IteratorAggregate, astfel încât puteți utiliza foreach pentru a răsfoi rezultatele. Este programat astfel încât rezultatele să fie încărcate doar pe măsură ce navigați, astfel încât, dacă aveți un număr mare de fișiere, nu așteaptă să fie citite toate.

Puteți, de asemenea, să primiți rezultatele ca o matrice de obiecte Nette\Utils\FileInfo, utilizând metoda collect(). Matricea nu este asociativă, ci numerică.

$array = $finder->findFiles('*.php')->collect();
versiune: 4.0