Class Nette\Utils\Finder makes browsing the directory structure really easy.
All examples assume the following class alias is defined:
use Nette\Utils\Finder;How to find all *.txt files in $dir directory without recursing subdirectories?
foreach (Finder::findFiles('*.txt')->in($dir) as $key => $file) {
echo $key; // $key is a string containing absolute filename with path
echo $file; // $file is an instance of SplFileInfo
}As a result, the finder returns instances of SplFileInfo.
If the directory does not exist, an UnexpectedValueException is thrown.
And what about searching for *.txt files in $dir including subdirectories? Instead of in(), use from():
foreach (Finder::findFiles('*.txt')->from($dir) as $file) {
echo $file;
}Search by more masks, even inside more directories within one iteration:
foreach (Finder::findFiles('*.txt', '*.php')
->in($dir1, $dir2) as $file) {
...
}Parameters can also be arrays:
foreach (Finder::findFiles($masks)->in($dirs) as $file) {
...
}Searching for *.txt files containing a number in the name:
foreach (Finder::findFiles('*[0-9]*.txt')->from($dir) as $file) {
...
}Searching for *.txt files, except those containing 'X' in the name:
foreach (Finder::findFiles('*.txt')
->exclude('*X*')->from($dir) as $file) {
...
}exclude() is specified just after findFiles(), thus it applies to filename.
Directories to omit can be specified using the exclude after from clause:
foreach (Finder::findFiles('*.php')
->from($dir)->exclude('temp', '.git') as $file) {
...
}Here exclude() is after from(), thus it applies to the directory name.
And now something a bit more complicated: searching for *.txt files located in subdirectories starting with 'te', but not 'temp':
foreach (Finder::findFiles('te*/*.txt')
->exclude('temp*/*')->from($dir) as $file) {
...
}Depth of search can be limited using the limitDepth() method.
In addition to files, it is possible to search for directories using Finder::findDirectories('subdir*'), or to search for files and directories: Finder::find('file.txt').
You can also filter results. For example by size. This way we will traverse the files of size between 100B and 200B:
foreach (Finder::findFiles('*.php')->size('>=', 100)->size('<=', 200)
->from($dir) as $file) {
...
}Or files changed in the last two weeks:
foreach (Finder::findFiles('*.php')->date('>', '- 2 weeks')
->from($dir) as $file) {
...
}Here we traverse PHP files with number of lines greater than 1000. As a filter we use a custom callback:
$finder = Finder::findFiles('*.php')->filter(function($file) {
return count(file($file->getPathname())) > 1000;
})->from($dir);Finder, find images larger than 50px Γ 50px:
foreach (Finder::findFiles('*')
->dimensions('>50', '>50')->from($dir) as $file) {
...
}It's possible to use custom streams, for example 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;
}Handy, right? You will certainly find a use for Finder in your applications.