Finder: wyszukiwanie plików
Potrzebujesz znaleźć pliki pasujące do określonej maski? Finder może ci pomóc. Jest to wszechstronne i szybkie narzędzie do przeglądania struktury katalogów.
Instalacja:
composer require nette/utils
W przykładach założono, że alias został utworzony:
use Nette\Utils\Finder;
Korzystanie z
Najpierw zobaczmy, jak można użyć Nette\Utils\Finder
do wypisania nazw plików z rozszerzeniami .txt
i .md
w bieżącym katalogu:
foreach (Finder::findFiles(['*.txt', '*.md']) as $name => $file) {
echo $file;
}
Domyślnym katalogiem dla wyszukiwania jest katalog bieżący, ale możesz go zmienić używając metod in() lub from(). Zmienna $file
jest instancją klasy FileInfo z wieloma przydatnymi metodami. Klucz $name
zawiera ścieżkę do pliku jako ciąg
znaków.
Na co zwrócić uwagę?
Oprócz metody findFiles()
istnieje również findDirectories()
, która przeszukuje tylko katalogi,
oraz find()
, która przeszukuje oba katalogi. Te metody są statyczne, więc można je wywołać bez tworzenia
instancji. Parametr maski jest opcjonalny, jeśli go nie określisz, wszystko jest przeszukiwane.
foreach (Finder::find() as $file) {
echo $file; // wszystkie pliki i katalogi są teraz wymienione
}
Użyj metod files()
i directories()
, aby dodać, co jeszcze należy wyszukać. Metody te mogą być
wywoływane wielokrotnie, a jako parametr można podać tablicę masek:
Finder::findDirectories('vendor') // wszystkie katalogi
->files(['*.php', '*.phpt']); // plus wszystkie pliki PHP
Alternatywą dla metod statycznych jest utworzenie instancji za pomocą new Finder
(świeży obiekt utworzony w
ten sposób niczego nie wyszukuje) i określenie, czego ma szukać za pomocą files()
i
directories()
:
(new Finder)
->directories() // wszystkie katalogi
->files('*.php'); // plus wszystkie pliki PHP
W masce można używać znaków wieloznacznych *
, **
, ?
a
[...]
. Możesz nawet określić w katalogach, na przykład src/*.php
będzie szukać wszystkich plików
PHP w katalogu src
.
Symlinki są również uważane za katalogi lub pliki.
Gdzie szukać?
Domyślnym katalogiem wyszukiwania jest katalog bieżący. Możesz to zmienić używając metod in()
i
from()
Jak widać z nazw metod, in()
przeszukuje tylko bieżący katalog, natomiast from()
przeszukuje jego podkatalogi (rekurencyjnie). Jeśli chcesz szukać rekurencyjnie w bieżącym katalogu, możesz użyć
from('.')
.
Możesz wywołać te metody wielokrotnie lub przekazać do nich wiele ścieżek jako tablice, wtedy pliki będą przeszukiwane
we wszystkich katalogach. Jeśli jeden z katalogów nie istnieje, rzucany jest wyjątek
Nette\UnexpectedValueException
.
Finder::findFiles('*.php')
->in(['src', 'tests']) // wyszukuje bezpośrednio w src/ i tests/
->from('vendor'); // wyszukuje również w podkatalogach vendor/
Ścieżki relatywne są względne w stosunku do bieżącego katalogu. Oczywiście można również określić ścieżki bezwzględne:
Finder::findFiles('*.php')
->in('/var/www/html');
Możesz użyć symboli wieloznacznych *
, **
, ?
. Můžete tak třeba pomocí cesty
src/*/*.php
w ścieżce, aby wyszukać wszystkie pliki PHP w katalogach drugiego poziomu w katalogu src
.
Symbol wieloznaczny **
, zwany globstar, jest potężnym atutem, ponieważ pozwala na
wyszukiwanie również w podkatalogach: użyj src/**/tests/*.php
, aby wyszukać wszystkie pliki PHP w katalogu
tests
znajdujące się w src
lub dowolnym jego podkatalogu.
Z drugiej strony, symbole wieloznaczne [...]
znaki nie są obsługiwane w ścieżce, tzn. nie mają specjalnego
znaczenia, aby uniknąć niepożądanego zachowania w przypadku, gdy użytkownik szuka in(__DIR__)
i przypadkowo w
ścieżce pojawiają się znaki []
.
Podczas wyszukiwania plików i katalogów w głąb, najpierw zwracany jest katalog nadrzędny, a następnie pliki w nim
zawarte, co można odwrócić za pomocą childFirst()
.
Żbiki
W masce można użyć kilku znaków specjalnych:
*
– nahrazuje libovolný počet libovolných znaků (kromě/
)**
– zastępuje dowolną liczbę dowolnych znaków, w tym/
(czyli może być przeszukiwany wielopoziomowo)?
– nahrazuje jeden libovolný znak (kromě/
)[a-z]
– zastępuje jeden znak z listy znaków w nawiasach kwadratowych[!a-z]
– zastępuje jeden znak spoza listy znaków w nawiasach kwadratowych
Przykłady zastosowania:
img/?.png
– pliki o jednoliterowej nazwie0.png
,1.png
,x.png
, itd.logs/[0-9][0-9][0-9][0-9]-[01][0-9]-[0-3][0-9].log
– pliki dziennika w formacieYYYY-MM-DD
src/**/tests/*
– pliki w katalogusrc/tests
,src/foo/tests
,src/foo/bar/tests
i tak dalej.docs/**.md
– wszystkie pliki z rozszerzeniem.md
we wszystkich podkatalogach katalogudocs
Z wyłączeniem
Użyj metody exclude()
, aby wykluczyć pliki i katalogi z wyszukiwań. Określasz maskę, do której plik nie
może pasować. Przykład wyszukiwania plików *.txt
z wyjątkiem tych zawierających w nazwie literę
X
:
Finder::findFiles('*.txt')
->exclude('*X*');
Użyj exclude()
aby pominąć przeglądane podkatalogi:
Finder::findFiles('*.php')
->from($dir)
->exclude('temp', '.git')
Filtrowanie
Finder oferuje kilka metod filtrowania wyników (czyli ich zmniejszania). Można je łączyć i nazywać wielokrotnie.
Użyj size()
, aby filtrować według rozmiaru pliku. W ten sposób znajdujemy pliki o rozmiarach od 100 do
200 bajtów:
Finder::findFiles('*.php')
->size('>=', 100)
->size('<=', 200);
Metoda date()
filtruje według daty ostatniej modyfikacji pliku. Wartości mogą być bezwzględne lub względne w
stosunku do bieżącej daty i czasu, na przykład w ten sposób można znaleźć pliki zmienione w ciągu ostatnich dwóch
tygodni:
Finder::findFiles('*.php')
->date('>', '-2 weeks')
->from($dir)
Obie funkcje rozumieją operatory >
, >=
, <
, <=
, =
,
!=
, <>
.
Finder umożliwia również filtrowanie wyników przy użyciu funkcji niestandardowych. Funkcja otrzymuje jako parametr obiekt
Nette\Utils\FileInfo
i musi zwrócić true
, aby włączyć plik do wyników.
Przykład: wyszukaj pliki PHP, które zawierają ciąg Nette
(wielkość liter nie ma znaczenia):
Finder::findFiles('*.php')
->filter(fn($file) => strcasecmp($file->read(), 'Nette') === 0);
Filtrowanie głębokości
Podczas wyszukiwania rekurencyjnego można ustawić maksymalną głębokość indeksowania za pomocą metody
limitDepth()
. Jeśli ustawisz limitDepth(1)
, indeksowane są tylko pierwsze podkatalogi,
limitDepth(0)
wyłącza indeksowanie głębokości, a wartość –1 anuluje limit.
Finder pozwala na wykorzystanie własnych funkcji do decydowania, do którego katalogu wejść podczas przeglądania. Funkcja
otrzymuje jako parametr obiekt Nette\Utils\FileInfo
i musi zwrócić true
, aby wejść do katalogu:
Finder::findFiles('*.php')
->descentFilter($file->getBasename() !== 'temp');
Sortowanie
Finder oferuje również kilka funkcji sortowania wyników.
Metoda sortByName()
sortuje wyniki według nazwy pliku. Sortowanie jest naturalne, tzn. poprawnie obsługuje
liczby w nazwach i zwraca np. foo1.txt
przed foo10.txt
.
Finder umożliwia również sortowanie przy użyciu funkcji niestandardowej. Przyjmuje dwa obiekty
Nette\Utils\FileInfo
jako parametry i musi zwrócić wynik porównania za pomocą operatora <=>
,
czyli -1
, 0
nebo 1
. Na przykład w ten sposób sortujemy pliki według wielkości:
$finder->sortBy(fn($a, $b) => $a->getSize() <=> $b->getSize());
Wiele różnych wyszukiwań
Jeśli musisz znaleźć wiele różnych plików w różnych lokalizacjach lub spełniających różne kryteria, użyj metody
append()
. Zwraca ona nowy obiekt Finder
, dzięki czemu możesz łączyć wywołania metod:
($finder = new Finder) // przechowuj pierwszego Findera w zmiennej $finder!
->files('*.php') // szukaj plików *.php w src/
->from('src')
->append()
->files('*.md') // w docs/ szukaj plików *.md
->from('docs')
->append()
->files('*.json'); // w bieżącym folderze szukaj plików *.json
Alternatywnie możesz użyć metody append()
, aby dodać określony plik (lub tablicę plików). Następnie zwraca
ten sam obiekt Finder
:
$finder = Finder::findFiles('*.txt')
->append(__FILE__);
FileInfo
Nette\Utils\FileInfo to klasa reprezentująca plik lub katalog w wynikach wyszukiwania. Jest to rozszerzenie klasy SplFileInfo, które dostarcza informacji takich jak rozmiar pliku, data ostatniej modyfikacji, nazwa, ścieżka itp.
Dodatkowo zapewnia metody zwracania ścieżek względnych, co jest przydatne podczas głębokiego przeglądania:
foreach (Finder::findFiles('*.jpg')->from('.') as $file) {
$absoluteFilePath = $file->getRealPath();
$relativeFilePath = $file->getRelativePathname();
}
Masz również metody odczytu i zapisu zawartości pliku:
foreach ($finder as $file) {
$contents = $file->read();
// ...
$file->write($contents);
}
Zwracanie wyników w postaci tablicy
Jak widać w przykładach, Finder implementuje interfejs IteratorAggregate
, więc możesz użyć
foreach
do przeglądania wyników. Jest zaprogramowany tak, że wyniki są ładowane tylko w trakcie przeglądania,
więc jeśli masz dużą liczbę plików, nie czeka na odczytanie ich wszystkich.
Możesz również zlecić zwrócenie wyników w postaci tablicy obiektów Nette\Utils\FileInfo
, używając metody
collect()
Tablica nie jest asocjacyjna, lecz numeryczna.
$array = $finder->findFiles('*.php')->collect();