Finder: fájlok keresése
Fájlokat kell találnia, amelyek megfelelnek egy adott maszknak? A Finder segít ebben. Ez egy sokoldalú és gyors eszköz a könyvtárstruktúra bejárására.
Telepítés:
composer require nette/utils
A példák feltételezik a következő alias létrehozását:
use Nette\Utils\Finder;
Használat
Először megmutatjuk, hogyan írhatja ki a .txt
és .md
kiterjesztésű fájlneveket az aktuális
könyvtárban a Nette\Utils\Finder segítségével:
foreach (Finder::findFiles(['*.txt', '*.md']) as $name => $file) {
echo $file;
}
A keresés alapértelmezett könyvtára az aktuális könyvtár, de ezt megváltoztathatja az in() vagy from() metódusokkal. A $file
változó a FileInfo osztály példánya, rengeteg hasznos metódussal. A $name
kulcsban a fájl
elérési útja található stringként.
Mit kell keresni?
A findFiles()
metódus mellett létezik a findDirectories()
, amely csak könyvtárakat keres, és a
find()
, amely mindkettőt keresi. Ezek a metódusok statikusak, így példány létrehozása nélkül hívhatók.
A maszk paraméter opcionális, ha nem adja meg, mindent megkeres.
foreach (Finder::find() as $file) {
echo $file; // most minden fájl és könyvtár kiíródik
}
A files()
és directories()
metódusokkal kiegészítheti, hogy mi mást kell keresni. A metódusok
ismételten hívhatók, és paraméterként maszkok tömbje is megadható:
Finder::findDirectories('vendor') // minden könyvtár
->files(['*.php', '*.phpt']); // plusz minden PHP fájl
A statikus metódusok alternatívája a példány létrehozása a new Finder
segítségével (az így
létrehozott friss objektum semmit sem keres), és a files()
és directories()
segítségével megadni,
mit kell keresni:
(new Finder)
->directories() // minden könyvtár
->files('*.php'); // plusz minden PHP fájl
A maszkban használhat helyettesítő karaktereket *
, **
,
?
és [...]
. Akár könyvtárakat is megadhat, például a src/*.php
megkeresi az összes
PHP fájlt a src
könyvtárban.
A szimbolikus linkek szintén könyvtárnak vagy fájlnak minősülnek.
Hol kell keresni?
A keresés alapértelmezett könyvtára az aktuális könyvtár. Ezt az in()
és from()
metódusokkal változtathatja meg. Ahogy a metódusnevekből is látható, az in()
csak az adott könyvtárban keres,
míg a from()
annak alkönyvtáraiban is keres (rekurzívan). Ha rekurzívan szeretne keresni az aktuális
könyvtárban, használhatja a from('.')
-ot.
Ezek a metódusok többször is hívhatók, vagy több elérési utat átadhat nekik tömbként, a fájlok ezután minden
könyvtárban keresve lesznek. Ha valamelyik könyvtár nem létezik, Nette\UnexpectedValueException
kivétel
dobódik.
Finder::findFiles('*.php')
->in(['src', 'tests']) // közvetlenül keres a src/ és tests/ könyvtárakban
->from('vendor'); // a vendor/ alkönyvtáraiban is keres
A relatív elérési utak az aktuális könyvtárhoz képest relatívak. Természetesen abszolút elérési utakat is meg lehet adni:
Finder::findFiles('*.php')
->in('/var/www/html');
Az elérési úton lehet használni helyettesítő karaktereket *
,
**
, ?
. Így például a src/*/*.php
elérési út segítségével keresheti az összes PHP
fájlt a src
könyvtár második szintű könyvtáraiban. A **
karakter, amit globstarnak neveznek, egy
erős aduász, mert lehetővé teszi az alkönyvtárakban való keresést is: a src/**/tests/*.php
segítségével
keresi az összes PHP fájlt a tests
könyvtárban, amely a src
-ben vagy annak bármely
alkönyvtárában található.
Ellenben a [...]
helyettesítő karakterek az elérési úton nem támogatottak, azaz nincs különleges
jelentésük, hogy elkerüljük a nem kívánt viselkedést abban az esetben, ha például az in(__DIR__)
-t keresi,
és véletlenül az elérési úton []
karakterek lesznek.
Fájlok és könyvtárak mélységi keresésekor először a szülőkönyvtárat adja vissza, csak azután a benne lévő
fájlokat, amit a childFirst()
segítségével meg lehet fordítani.
Helyettesítő karakterek
A maszkban több speciális karaktert használhat:
*
– tetszőleges számú tetszőleges karaktert helyettesít (kivéve/
)**
– tetszőleges számú tetszőleges karaktert helyettesít, beleértve a/
-t is (azaz többszintű keresés lehetséges)?
– egy tetszőleges karaktert helyettesít (kivéve/
)[a-z]
– egy karaktert helyettesít a szögletes zárójelben lévő karakterlistából[!a-z]
– egy karaktert helyettesít a szögletes zárójelben lévő karakterlistán kívül
Használati példák:
img/?.png
– egybetűs nevű fájlok0.png
,1.png
,x.png
, stb.logs/[0-9][0-9][0-9][0-9]-[01][0-9]-[0-3][0-9].log
–YYYY-MM-DD
formátumú naplóksrc/**/tests/*
– fájlok asrc/tests
,src/foo/tests
,src/foo/bar/tests
könyvtárakban és így tovább.docs/**.md
– minden.md
kiterjesztésű fájl adocs
könyvtár összes alkönyvtárában
Kizárás
Az exclude()
metódussal kizárhat fájlokat és könyvtárakat a keresésből. Megadja a maszkot, amelynek a
fájl nem felelhet meg. Példa *.txt
fájlok keresésére, kivéve azokat, amelyek nevében X
betű
szerepel:
Finder::findFiles('*.txt')
->exclude('*X*');
A bejárt alkönyvtárak kihagyásához használja az exclude()
-ot:
Finder::findFiles('*.php')
->from($dir)
->exclude('temp', '.git')
Szűrés
A Finder több metódust kínál az eredmények szűrésére (azaz azok csökkentésére). Kombinálhatja őket és ismételten hívhatja.
A size()
segítségével fájlméret szerint szűrünk. Így találunk 100 és 200 bájt közötti méretű
fájlokat:
Finder::findFiles('*.php')
->size('>=', 100)
->size('<=', 200);
A date()
metódus a fájl utolsó módosításának dátuma szerint szűr. Az értékek lehetnek abszolútak vagy
relatívak az aktuális dátumhoz és időhöz képest, például így találjuk meg az elmúlt két hétben módosított
fájlokat:
Finder::findFiles('*.php')
->date('>', '-2 weeks')
->from($dir)
Mindkét függvény érti a >
, >=
, <
, <=
, =
,
!=
, <>
operátorokat.
A Finder lehetővé teszi az eredmények szűrését saját függvények segítségével is. A függvény paraméterként kap
egy Nette\Utils\FileInfo
objektumot, és true
-t kell visszaadnia, hogy a fájl bekerüljön az
eredmények közé.
Példa: olyan PHP fájlok keresése, amelyek tartalmazzák a Nette
stringet (kis- és nagybetűk figyelmen kívül
hagyásával):
Finder::findFiles('*.php')
->filter(fn($file) => strcasecmp($file->read(), 'Nette') === 0);
Mélységi szűrés
Rekurzív kereséskor beállíthatja a maximális bejárási mélységet a limitDepth()
metódussal. Ha
beállítja a limitDepth(1)
-et, csak az első alkönyvtárakat járja be, a limitDepth(0)
kikapcsolja a
mélységi bejárást, és a –1 érték törli a korlátot.
A Finder lehetővé teszi saját függvényekkel eldönteni, melyik könyvtárba lépjen be a bejárás során. A függvény
paraméterként kap egy Nette\Utils\FileInfo
objektumot, és true
-t kell visszaadnia, hogy belépjen a
könyvtárba:
Finder::findFiles('*.php')
->descentFilter($file->getBasename() !== 'temp');
Rendezés
A Finder több funkciót is kínál az eredmények rendezésére.
A sortByName()
metódus az eredményeket fájlnevek szerint rendezi. A rendezés naturális, azaz helyesen kezeli
a számokat a nevekben, és például a foo1.txt
-t adja vissza a foo10.txt
előtt.
A Finder lehetővé teszi a rendezést saját függvénnyel is. Paraméterként két Nette\Utils\FileInfo
objektumot kap, és vissza kell adnia az <=>
operátorral végzett összehasonlítás eredményét, azaz
-1
, 0
vagy 1
. Például így rendezzük a fájlokat méret szerint:
$finder->sortBy(fn($a, $b) => $a->getSize() <=> $b->getSize());
Több különböző keresés
Ha több különböző fájlt kell találnia különböző helyeken, vagy más kritériumoknak megfelelőket, használja az
append()
metódust. Új Finder
objektumot ad vissza, így lehetséges a metódushívásokat
láncolni:
($finder = new Finder) // a $finder változóba elmentjük az első Findert!
->files('*.php') // a src/-ben *.php fájlokat keresünk
->from('src')
->append()
->files('*.md') // a docs/-ban *.md fájlokat keresünk
->from('docs')
->append()
->files('*.json'); // az aktuális mappában *.json fájlokat keresünk
Alternatívaként használható az append()
metódus egy konkrét fájl (vagy fájlok tömbjének)
hozzáadására. Akkor ugyanazt a Finder
objektumot adja vissza:
$finder = Finder::findFiles('*.txt')
->append(__FILE__);
FileInfo
A Nette\Utils\FileInfo egy fájlt vagy könyvtárat reprezentáló osztály a keresési eredményekben. Ez a SplFileInfo osztály kiterjesztése, amely információkat nyújt, mint például a fájlméret, utolsó módosítás dátuma, név, elérési út, stb.
Ezenkívül metódusokat biztosít a relatív elérési út visszaadására, ami hasznos a mélységi bejárás során:
foreach (Finder::findFiles('*.jpg')->from('.') as $file) {
$absoluteFilePath = $file->getRealPath();
$relativeFilePath = $file->getRelativePathname();
}
Továbbá rendelkezésre állnak metódusok a fájl tartalmának olvasására és írására:
foreach ($finder as $file) {
$contents = $file->read();
// ...
$file->write($contents);
}
Eredmények visszaadása tömbként
Ahogy a példákban látható volt, a Finder implementálja az IteratorAggregate
interfészt, így
használhatja a foreach
-et az eredmények bejárására. Úgy van programozva, hogy az eredmények csak a bejárás
során töltődnek be, így ha nagy mennyiségű fájlja van, nem várja meg, amíg mind beolvasódik.
Az eredményeket objektumok tömbjeként is visszaadhatja, méghozzá a collect()
metódussal. A tömb nem
asszociatív, hanem numerikus.
$array = $finder->findFiles('*.php')->collect();