Vyhledávání souborů: Finder
Třída Nette\Utils\Finder zjednodušuje procházení adresářovou strukturou na disku.
Všechny příklady předpokládají vytvořený alias:
use Nette\Utils\Finder;
Hledání souborů
Jak vyhledat soubory *.txt
v adresáři $dir
bez procházení podadresářů?
foreach (Finder::findFiles('*.txt')->in($dir) as $key => $file) {
echo $key; // $key je řetězec s názvem souboru včetně cesty
echo $file; // $file je objektem SplFileInfo
}
Jako výsledek hledání získáme instance třídy SplFileInfo.
Pokud by adresář neexistoval, vyhodí se výjimka UnexpectedValueException
.
A co třeba hledání souborů *.txt
v adresáři $dir
a všech jeho podadresářích? Místo
in()
použijeme from()
:
foreach (Finder::findFiles('*.txt')->from($dir) as $file) {
echo $file;
}
Hledání podle více masek a dokonce z více adresářů v rámci jedné iterace:
foreach (Finder::findFiles('*.txt', '*.php')
->in($dir1, $dir2) as $file) {
...
}
přičemž parametry lze zadat i ve formě polí:
foreach (Finder::findFiles($masks)->in($dirs) as $file) {
...
}
Hledání souborů *.txt
obsahujících číslici v názvu:
foreach (Finder::findFiles('*[0-9]*.txt')->from($dir) as $file) {
...
}
Hledání souborů *.txt
kromě těch, co obsahují v názvu písmeno X
foreach (Finder::findFiles('*.txt')
->exclude('*X*')->from($dir) as $file) {
...
}
exclude()
je uvedeno těsně za findFiles()
, takže se vztahuje k němu.
Adresáře, kterým se chceme při procházení do hloubky zcela vyhnout, uvedeme v exclude
za klauzulí
from
:
foreach (Finder::findFiles('*.php')
->from($dir)->exclude('temp', '.git') as $file) {
...
}
Tady se exclude()
vztahuje na from()
.
A teď něco malinko složitějšího: hledání souborů *.txt
umístěných v podadresáři začínajícím na
te
, ale nikoliv temp
:
foreach (Finder::findFiles('te*/*.txt')
->exclude('temp*/*')->from($dir) as $file) {
...
}
Omezit hloubku procházení lze metodou limitDepth()
.
Hledání adresářů
Kromě souborů lze hledat i adresáře přes Finder::findDirectories('subdir*')
nebo obojí
Finder::find('file.txt')
.
Ve verzi 2.0 se maska vztahuje jen na soubory, od verze 2.1 i na adresáře.
Filtrování
Dále je možné výsledky filtrovat. Například podle velikosti. Takto projdeme soubory s velikostí v rozmezí 100B až 200B:
foreach (Finder::findFiles('*.php')->size('>=', 100)->size('<=', 200)
->from($dir) as $file) {
...
}
Nebo soubory změněné v posledních dvou týdnech:
foreach (Finder::findFiles('*.php')->date('>', '- 2 weeks')
->from($dir) as $file) {
...
}
Zde se prochází soubory PHP s počtem řádku větším než 1000. Jako filtr použijeme vlastní callback:
$finder = Finder::findFiles('*.php')->filter(function ($file) {
return count(file($file->getPathname())) > 1000;
})->from($dir);
Lze jít ještě dál a třídu Nette\Utils\Finder
za využití rozšiřujících metod rozšířit například o metodu
dimensions
:
Finder::extensionMethod('dimensions', function($finder, $width, $height){
if (!preg_match('#^([=<>!]+)\s*(\d+)$#i', $width, $mW)
|| !preg_match('#^([=<>!]+)\s*(\d+)$#i', $height, $mH)
) {
throw new InvalidArgumentException('Invalid dimensions predicate format.');
}
return $finder->filter(function ($file) use ($mW, $mH) {
return $file->getSize() >= 12 && ($size = getimagesize($file->getPathname()))
&& (!$mW || Finder::compare($size[0], $mW[1], $mW[2]))
&& (!$mH || Finder::compare($size[1], $mH[1], $mH[2]));
});
});
Findere, najdi obrázky s rozměry většími než 50px × 50px:
foreach (Finder::findFiles('*')
->dimensions('>50', '>50')->from($dir) as $file) {
...
}
Propojení na Amazon S3
Lze také využít uživatelské streamy, kupříkladu Zend_Service_Amazon_S3:
$s3 = new Zend_Service_Amazon_S3($key, $secret);
$s3->registerStreamWrapper('s3');
foreach (Finder::findFiles('photos*')
->size('<=', 1e6)->in('s3://bucket-name') as $file) {
echo $file;
}
Šikovné, že? Finder určitě najde využití ve vašich aplikacích.
Viz také: