Finder: iskanje datotek
Potrebujete najti datoteke, ki ustrezajo določeni maski? Finder vam bo pri tem pomagal. Je vsestransko in hitro orodje za brskanje po strukturi imenikov.
Namestitev:
composer require nette/utils
Primeri predpostavljajo ustvarjen vzdevek:
use Nette\Utils\Finder;
Uporaba
Najprej si poglejmo, kako lahko z uporabo Nette\Utils\Finder izpišete imena datotek s končnicami
.txt
in .md
v trenutnem imeniku:
foreach (Finder::findFiles(['*.txt', '*.md']) as $name => $file) {
echo $file;
}
Privzeti imenik za iskanje je trenutni imenik, vendar ga lahko spremenite z metodama in() ali
from(). Spremenljivka $file
je instanca razreda FileInfo z veliko uporabnimi
metodami. V ključu $name
je pot do datoteke kot niz.
Kaj iskati?
Poleg metode findFiles()
obstaja tudi findDirectories()
, ki išče samo imenike, in
find()
, ki išče oboje. Te metode so statične, zato jih je mogoče klicati brez ustvarjanja instance. Parameter
z masko je neobvezen, če ga ne navedete, se poišče vse.
foreach (Finder::find() as $file) {
echo $file; // zdaj se izpišejo vse datoteke in imeniki
}
Z metodama files()
in directories()
lahko dodate, kaj še želite iskati. Metode je mogoče klicati
večkrat in kot parameter lahko navedete tudi polje mask:
Finder::findDirectories('vendor') // vsi imeniki
->files(['*.php', '*.phpt']); // plus vse PHP datoteke
Alternativa statičnim metodam je ustvarjanje instance z new Finder
(tako ustvarjen svež objekt ne išče
ničesar) in navedbo, kaj iskati, z uporabo files()
in directories()
:
(new Finder)
->directories() // vsi imeniki
->files('*.php'); // plus vse PHP datoteke
V maski lahko uporabljate nadomestne znake *
, **
, ?
in [...]
. Lahko celo določite imenike, na primer src/*.php
poišče vse PHP datoteke v imeniku
src
.
Simbolične povezave se prav tako štejejo za imenike ali datoteke.
Kje iskati?
Privzeti imenik za iskanje je trenutni imenik. Spremenite ga z metodama in()
in from()
. Kot je
razvidno iz imen metod, in()
išče samo v danem imeniku, medtem ko from()
išče tudi v njegovih
podimenikih (rekurzivno). Če želite iskati rekurzivno v trenutnem imeniku, lahko uporabite from('.')
.
Te metode je mogoče klicati večkrat ali jim posredovati več poti kot polje, datoteke se bodo nato iskale v vseh imenikih.
Če kateri od imenikov ne obstaja, se sproži izjema Nette\UnexpectedValueException
.
Finder::findFiles('*.php')
->in(['src', 'tests']) // išče neposredno v src/ in tests/
->from('vendor'); // išče tudi v podimenikih vendor/
Relativne poti so relativne glede na trenutni imenik. Seveda lahko navedete tudi absolutne poti:
Finder::findFiles('*.php')
->in('/var/www/html');
V poti je mogoče uporabiti nadomestne znake nadomestne znake *
,
**
, ?
. Tako lahko na primer s potjo src/*/*.php
iščete vse PHP datoteke v imenikih
druge ravni v imeniku src
. Znak **
, imenovan globstar, je močan adut, saj omogoča iskanje tudi
v podimenikih: z src/**/tests/*.php
iščete vse PHP datoteke v imeniku tests
, ki se nahaja v
src
ali katerem koli njegovem podimeniku.
Nasprotno pa nadomestni znaki [...]
v poti niso podprti, tj. nimajo posebnega pomena, da ne bi prišlo do
nezaželenega vedenja v primeru, da bi iskali na primer in(__DIR__)
in bi se v poti slučajno pojavili znaki
[]
.
Pri iskanju datotek in imenikov v globino se najprej vrne nadrejeni imenik in šele nato datoteke, ki jih vsebuje, kar je
mogoče obrniti z uporabo childFirst()
.
Nadomestni znaki
V maski lahko uporabljate več posebnih znakov:
*
– nadomešča poljubno število poljubnih znakov (razen/
)**
– nadomešča poljubno število poljubnih znakov, vključno z/
(tj. mogoče je iskati večnivojsko)?
– nadomešča en poljuben znak (razen/
)[a-z]
– nadomešča en znak s seznama znakov v oglatih oklepajih[!a-z]
– nadomešča en znak izven seznama znakov v oglatih oklepajih
Primeri uporabe:
img/?.png
– datoteke z enočrkovnim imenom0.png
,1.png
,x.png
, itd.logs/[0-9][0-9][0-9][0-9]-[01][0-9]-[0-3][0-9].log
– dnevniki v formatuYYYY-MM-DD
src/**/tests/*
– datoteke v imenikihsrc/tests
,src/foo/tests
,src/foo/bar/tests
in tako naprej.docs/**.md
– vse datoteke s končnico.md
v vseh podimenikih imenikadocs
Izključitev
Z metodo exclude()
je mogoče izključiti datoteke in imenike iz iskanja. Navedete masko, ki ji datoteka ne sme
ustrezati. Primer iskanja datotek *.txt
, razen tistih, ki v imenu vsebujejo črko X
:
Finder::findFiles('*.txt')
->exclude('*X*');
Za izpustitev pregledanih podimenikov uporabite exclude()
:
Finder::findFiles('*.php')
->from($dir)
->exclude('temp', '.git')
Filtriranje
Finder ponuja več metod za filtriranje rezultatov (tj. njihovo zmanjšanje). Lahko jih kombinirate in kličete večkrat.
Z size()
filtriramo glede na velikost datoteke. Tako najdemo datoteke z velikostjo v območju od 100 do
200 bajtov:
Finder::findFiles('*.php')
->size('>=', 100)
->size('<=', 200);
Metoda date()
filtrira glede na datum zadnje spremembe datoteke. Vrednosti so lahko absolutne ali relativne glede
na trenutni datum in čas, na primer, tako najdemo datoteke, spremenjene v zadnjih dveh tednih:
Finder::findFiles('*.php')
->date('>', '-2 weeks')
->from($dir)
Obe funkciji razumeta operatorje >
, >=
, <
, <=
, =
,
!=
, <>
.
Finder omogoča tudi filtriranje rezultatov z uporabo lastnih funkcij. Funkcija prejme kot parameter objekt
Nette\Utils\FileInfo
in mora vrniti true
, da se datoteka vključi v rezultate.
Primer: iskanje PHP datotek, ki vsebujejo niz Nette
(ne glede na velikost črk):
Finder::findFiles('*.php')
->filter(fn($file) => strcasecmp($file->read(), 'Nette') === 0);
Globinsko filtriranje
Pri rekurzivnem iskanju lahko nastavite največjo globino brskanja z metodo limitDepth()
. Če nastavite
limitDepth(1)
, se preiskujejo samo prvi podimeniki, limitDepth(0)
izklopi globinsko brskanje in
vrednost –1 prekliče omejitev.
Finder omogoča z uporabo lastnih funkcij odločanje, v kateri imenik naj se vstopi med brskanjem. Funkcija prejme kot
parameter objekt Nette\Utils\FileInfo
in mora vrniti true
, da se vstopi v imenik:
Finder::findFiles('*.php')
->descentFilter($file->getBasename() !== 'temp');
Razvrščanje
Finder ponuja tudi več funkcij za razvrščanje rezultatov.
Metoda sortByName()
razvršča rezultate po imenih datotek. Razvrščanje je naravno, torej pravilno obravnava
števila v imenih in vrača npr. foo1.txt
pred foo10.txt
.
Finder omogoča tudi razvrščanje z uporabo lastne funkcije. Ta prejme kot parameter dva objekta
Nette\Utils\FileInfo
in mora vrniti rezultat primerjave z operatorjem <=>
, torej -1
,
0
ali 1
. Na primer, tako razvrstimo datoteke po velikosti:
$finder->sortBy(fn($a, $b) => $a->getSize() <=> $b->getSize());
Več različnih iskanj
Če morate najti več različnih datotek na različnih lokacijah ali ki izpolnjujejo druga merila, uporabite metodo
append()
. Vrne nov objekt Finder
, zato je mogoče verižiti klice metod:
($finder = new Finder) // v spremenljivko $finder shranimo prvi Finder!
->files('*.php') // v src/ iščemo datoteke *.php
->from('src')
->append()
->files('*.md') // v docs/ iščemo datoteke *.md
->from('docs')
->append()
->files('*.json'); // v trenutni mapi iščemo datoteke *.json
Alternativno lahko uporabite metodo append()
za dodajanje določene datoteke (ali polja datotek). Nato vrne isti
objekt Finder
:
$finder = Finder::findFiles('*.txt')
->append(__FILE__);
FileInfo
Nette\Utils\FileInfo je razred, ki predstavlja datoteko ali imenik v rezultatih iskanja. Gre za razširitev razreda SplFileInfo, ki zagotavlja informacije, kot so velikost datoteke, datum zadnje spremembe, ime, pot itd.
Poleg tega ponuja metode za vračanje relativne poti, kar je uporabno pri globinskem brskanju:
foreach (Finder::findFiles('*.jpg')->from('.') as $file) {
$absoluteFilePath = $file->getRealPath();
$relativeFilePath = $file->getRelativePathname();
}
Nadalje imate na voljo metode za branje in pisanje vsebine datoteke:
foreach ($finder as $file) {
$contents = $file->read();
// ...
$file->write($contents);
}
Vračanje rezultatov kot polje
Kot je bilo videti v primerih, Finder implementira vmesnik IteratorAggregate
, zato lahko uporabite
foreach
za pregledovanje rezultatov. Programiran je tako, da se rezultati nalagajo samo med pregledovanjem, tako da
če imate veliko število datotek, ni treba čakati, da se vse preberejo.
Rezultate lahko dobite tudi kot polje objektov Nette\Utils\FileInfo
z metodo collect()
. Polje ni
asociativno, ampak numerično.
$array = $finder->findFiles('*.php')->collect();