Kereső: Fájlkeresés

Meg kell találnia egy bizonyos maszknak megfelelő fájlokat? A Finder segíthet. Ez egy sokoldalú és gyors eszköz a könyvtárstruktúra böngészésére.

Telepítés:

composer require nette/utils

A példák feltételezik egy alias létrehozását:

use Nette\Utils\Finder;

A használata

Először is nézzük meg, hogyan használhatjuk a Nette\Utils\Finder programot a .txt és .md kiterjesztésű fájlnevek listázására az aktuális könyvtárban:

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 az in() vagy from() metódusokkal megváltoztathatjuk. A $file változó a FileInfo osztály egy példánya, amely sok hasznos metódussal rendelkezik. A $name kulcs a fájl elérési útvonalát tartalmazza sztringként.

Mit keressünk?

A findFiles() módszer mellett létezik a findDirectories(), amely csak a könyvtárakban keres, és a find(), amely mindkettőben keres. Ezek a metódusok statikusak, tehát példány létrehozása nélkül hívhatók. A maszk paraméter opcionális, ha nem adjuk meg, mindent átkutat.

foreach (Finder::find() as $file) {
	echo $file; // most már minden fájl és könyvtár fel van sorolva.
}

A files() és a directories() metódusokkal adhatjuk meg, hogy mit keressünk még. A metódusok ismételten meghívhatók, és paraméterként megadható a maszkok tömbje:

Finder::findDirectories('vendor') // az összes könyvtárat
	->files(['*.php', '*.phpt']); // valamint az összes PHP fájl

A statikus módszerek alternatívája, hogy létrehozunk egy példányt a new Finder segítségével (az így létrehozott friss objektum nem keres semmit), és megadjuk, hogy mit keressünk a files() és a directories() segítségével:

(new Finder)
	->directories() // az összes könyvtárat
	->files('*.php'); // valamint az összes PHP fájl

Használhat vadkártyákat *, **, ? and [...] a maszkban. Megadhat könyvtárakat is, például a src/*.php a src könyvtárban található összes PHP-fájlt megkeresi.

A szimbolikus hivatkozások szintén könyvtáraknak vagy fájloknak minősülnek.

Az alapértelmezett keresési könyvtár az aktuális könyvtár. Ezt a in() és a from() módszerekkel módosíthatja. Amint a metódusnevekből látható, a in() csak az aktuális könyvtárban keres, míg a from() annak alkönyvtáraiban is (rekurzívan). Ha rekurzívan akarsz keresni az aktuális könyvtárban, használhatod a from('.').

Ezeket a metódusokat többször is meg lehet hívni, vagy több elérési utat is átadhatunk nekik tömbként, akkor a fájlok minden könyvtárban keresésre kerülnek. Ha az egyik könyvtár nem létezik, akkor a Nette\UnexpectedValueException eredményt kapjuk.

Finder::findFiles('*.php')
	->in(['src', 'tests']) // közvetlenül a src/ és tests/ fájlokban keres.
	->from('vendor'); // keres a vendor/ alkönyvtárakban is

A relatív elérési utak az aktuális könyvtárhoz képest relatívak. Természetesen abszolút elérési utak is megadhatók:

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

Wildcards wildcards *, **, ? can be used in the path. For example, you can use the path src/*/*.php a src könyvtár második szintű könyvtáraiban található összes PHP fájl kereséséhez. A ** karakter, az úgynevezett globstar egy erős aduász, mert lehetővé teszi az alkönyvtárakban való keresést is: a src/**/tests/*.php használatával a tests könyvtárban található összes PHP-fájlt kereshetjük, amelyek a src könyvtárban vagy annak bármelyik alkönyvtárában találhatók.

Másrészt a jokerek [...] karakterek nem támogatottak az elérési útvonalban, azaz nincs speciális jelentésük, hogy elkerüljük a nem kívánt viselkedést abban az esetben, ha például a in(__DIR__) címre keresünk, és véletlenül [] karakterek jelennek meg az elérési útvonalban.

A fájlok és könyvtárak mélységi keresésekor a rendszer először a szülő könyvtárat adja vissza, majd az abban található fájlokat, ami a childFirst() segítségével megfordítható.

Jokerjelek

A maszkban több speciális karaktert is használhat:

  • * – replaces any number of arbitrary characters (except /)
  • ** – tetszőleges számú tetszőleges karaktert helyettesít, beleértve a /-t is (azaz többszintű keresés is lehetséges).
  • ? – replaces one arbitrary character (except /)
  • [a-z] – egy karaktert helyettesít a szögletes zárójelben lévő karakterek listájából.
  • [!a-z] – egy karaktert helyettesít a szögletes zárójelben lévő karakterek listáján kívül.

Használati példák:

  • img/?.png – 0.png, 1.png, x.png, stb.
  • logs/[0-9][0-9][0-9][0-9]-[01][0-9]-[0-3][0-9].log – naplófájlok a következő formátumban YYYY-MM-DD
  • src/**/tests/* – a src/tests, src/foo/tests, src/foo/bar/tests stb. könyvtárban található fájlok.
  • docs/**.md – a .md kiterjesztésű összes fájl a könyvtár összes alkönyvtárában. docs

A kivételével.

A exclude() módszerrel kizárhat fájlokat és könyvtárakat a keresésből. Megad egy maszkot, amelynek a fájl nem felelhet meg. Példa a *.txt fájlok keresésére, kivéve azokat, amelyek nevében szerepel az X betű:

Finder::findFiles('*.txt')
	->exclude('*X*');

A exclude() használatával kihagyhatja a böngészett alkönyvtárakat:

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

Szűrés:

A Finder többféle módszert kínál a találatok szűrésére (azaz csökkentésére). Ezeket kombinálhatja és többször is meghívhatja.

A size() segítségével szűrhet a fájlméret szerint. Így a 100 és 200 bájt közötti méretű fájlokat találjuk meg:

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

A date() módszer a fájl utolsó módosításának dátuma alapján szűr. Az értékek lehetnek abszolút vagy az aktuális dátumhoz és időhöz viszonyítottak, 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 egyéni függvények segítségével is. A függvény paraméterként egy Nette\Utils\FileInfo objektumot kap, és vissza kell adnia a true címet ahhoz, hogy a fájl bekerüljön az eredmények közé.

Példa: A Nette karakterláncot tartalmazó PHP-fájlok keresése (nagy- és kisbetűket nem érzékeny):

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

Mélységi szűrés

Rekurzív keresés esetén a limitDepth() módszerrel beállíthatja a maximális feltérképezési mélységet. A limitDepth(1) beállítása esetén csak az első alkönyvtárak kerülnek feltérképezésre, a limitDepth(0) letiltja a mélységi feltérképezést, a –1 érték pedig törli a korlátozást.

A Finder lehetővé teszi, hogy saját függvényei segítségével döntse el, melyik könyvtárba lépjen be a böngészés során. A függvény paraméterként egy Nette\Utils\FileInfo objektumot kap, és a könyvtárba való belépéshez vissza kell adnia a true értéket:

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() módszer az eredményeket fájlnév szerint rendezi. A rendezés természetes, azaz helyesen kezeli a nevekben szereplő számokat, és például a foo1.txt -t a foo10.txt előtt adja vissza.

A Finder lehetővé teszi az egyéni funkcióval történő rendezést is. Ez két Nette\Utils\FileInfo objektumot vesz fel paraméterként, és az összehasonlítás eredményét kell visszaadnia az operátorral <=>, azaz -1, 0 nebo 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ő helyen lévő vagy különböző feltételeknek megfelelő fájlt kell keresnie, használja a append() módszert. Ez egy új Finder objektumot ad vissza, így a metódushívások láncolhatók:

($finder = new Finder) // tároljuk az első Finder-t a $finder változóban!
	->files('*.php') // *.php fájlokat keresünk a src/ könyvtárban.
	->from('src')
	->append()
	->files('*.md') // a docs/-ban keres *.md fájlokat
	->from('docs')
	->append()
	->files('*.json'); // az aktuális mappában keressük a *.json fájlokat.

Alternatívaként használhatja a append() metódust egy adott fájl (vagy fájlok tömbjének) hozzáadásához. Ekkor ugyanazt az objektumot adja vissza Finder:

$finder = Finder::findFiles('*.txt')
	->append(__FILE__);

FileInfo

ANette\Utils\FileInfo egy osztály, amely egy fájlt vagy könyvtárat reprezentál a keresési eredményekben. Ez a SplFileInfo osztály kiterjesztése, amely olyan információkat szolgáltat, mint a fájl mérete, utolsó módosítás dátuma, neve, elérési útja stb.

Ezen kívül metódusokat biztosít a relatív elérési utak visszaadására, ami hasznos a mélységi böngészés során:

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

Vannak módszerei a fájl tartalmának olvasására és írására is:

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

Eredmények visszaadása tömbként

Amint a példákban láttuk, a Finder megvalósítja a IteratorAggregate interfészt , így a foreach segítségével böngészhetünk az eredmények között. Úgy van programozva, hogy az eredmények csak a böngészés közben töltődnek be, így ha nagyszámú fájlod van, nem várja meg, hogy mindet beolvassa.

A collect() metódus segítségével az eredményeket Nette\Utils\FileInfo objektumok tömbjeként is visszakaphatja. A tömb nem asszociatív, hanem numerikus.

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