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
}
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'). V takovém případě se maska vztahuje
na soubory, nikoliv 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é:
lejmr | 6. 5. 2012, 15:30 | comment
Je zde nějaká možnost třídění výsledků? Nakonec data jsou uložená v SPL, tak by to bylo možné… klidně se na to podívám, ale jestli na tom někdo pracuje?