Finder: Dateisuche
Müssen Sie Dateien finden, die einer bestimmten Maske entsprechen? Der Finder kann Ihnen helfen. Er ist ein vielseitiges und schnelles Werkzeug zum Durchsuchen der Verzeichnisstruktur.
Installation:
composer require nette/utils
Die Beispiele gehen davon aus, dass ein Alias erstellt wurde:
use Nette\Utils\Finder;
Verwendung von
Sehen wir uns zunächst an, wie Sie Nette\Utils\Finder
verwenden können, um die Dateinamen mit den Erweiterungen .txt
und .md
im aktuellen Verzeichnis
aufzulisten:
foreach (Finder::findFiles(['*.txt', '*.md']) as $name => $file) {
echo $file;
}
Das Standardverzeichnis für die Suche ist das aktuelle Verzeichnis, aber Sie können es mit den Methoden in() oder from() ändern. Die Variable $file
ist eine Instanz der Klasse FileInfo mit vielen nützlichen Methoden. Der Schlüssel $name
enthält den Pfad zur Datei
als String.
Wonach soll gesucht werden?
Neben der Methode findFiles()
gibt es auch findDirectories()
, die nur Verzeichnisse durchsucht, und
find()
, die beide durchsucht. Diese Methoden sind statisch, d.h. sie können aufgerufen werden, ohne eine Instanz zu
erzeugen. Der Parameter mask ist optional, wenn Sie ihn nicht angeben, wird alles durchsucht.
foreach (Finder::find() as $file) {
echo $file; // jetzt sind alle Dateien und Verzeichnisse aufgelistet
}
Verwenden Sie die Methoden files()
und directories()
, um hinzuzufügen, wonach sonst noch gesucht
werden soll. Die Methoden können wiederholt aufgerufen werden und ein Array von Masken kann als Parameter übergeben werden:
Finder::findDirectories('vendor') // alle Verzeichnisse
->files(['*.php', '*.phpt']); // sowie alle PHP-Dateien
Eine Alternative zu statischen Methoden besteht darin, mit new Finder
eine Instanz zu erstellen (das auf diese
Weise neu erstellte Objekt sucht nach nichts) und mit files()
und directories()
anzugeben, wonach
gesucht werden soll:
(new Finder)
->directories() // alle Verzeichnisse
->files('*.php'); // sowie alle PHP-Dateien
Sie können Wildcards *
, **
verwenden, ?
and
[...]
in der Maske verwenden. Sie können sogar Verzeichnisse angeben, z. B. src/*.php
sucht nach allen
PHP-Dateien im Verzeichnis src
.
Symlinks werden auch als Verzeichnisse oder Dateien betrachtet.
Wo soll gesucht werden?
Das Standard-Suchverzeichnis ist das aktuelle Verzeichnis. Sie können dies ändern, indem Sie die Methoden in()
und from()
verwenden. Wie Sie aus den Namen der Methoden ersehen können, durchsucht in()
nur das
aktuelle Verzeichnis, während from()
auch die Unterverzeichnisse durchsucht (rekursiv). Wenn Sie rekursiv im
aktuellen Verzeichnis suchen wollen, können Sie from('.')
verwenden.
Diese Methoden können mehrfach aufgerufen werden oder Sie können ihnen mehrere Pfade als Arrays übergeben, dann werden
Dateien in allen Verzeichnissen gesucht. Wenn eines der Verzeichnisse nicht existiert, wird ein
Nette\UnexpectedValueException
geworfen.
Finder::findFiles('*.php')
->in(['src', 'tests']) // sucht direkt in src/ und tests/
->from('vendor'); // sucht auch in den Unterverzeichnissen von vendor/
Relative Pfade sind relativ zum aktuellen Verzeichnis. Es können natürlich auch absolute Pfade angegeben werden:
Finder::findFiles('*.php')
->in('/var/www/html');
Mit den Platzhaltern *
, **
, ?
can be used in the path. For
example, you can use the path src/*/*.php
können Sie nach allen PHP-Dateien in den Verzeichnissen der zweiten Ebene
im Verzeichnis src
suchen. Das Zeichen **
, globstar genannt, ist ein mächtiger Trumpf, weil es Ihnen
erlaubt, auch Unterverzeichnisse zu durchsuchen: Verwenden Sie src/**/tests/*.php
, um nach allen PHP-Dateien im
Verzeichnis tests
zu suchen, das sich in src
oder einem seiner Unterverzeichnisse befindet.
Andererseits werden Wildcards [...]
Zeichen werden im Pfad nicht unterstützt, d.h. sie haben keine besondere
Bedeutung, um unerwünschtes Verhalten zu vermeiden, falls Sie z.B. nach in(__DIR__)
suchen und zufällig
[]
Zeichen im Pfad erscheinen.
Bei der Suche nach Dateien und Verzeichnissen in der Tiefe wird zuerst das übergeordnete Verzeichnis zurückgegeben und dann
die darin enthaltenen Dateien, was sich mit childFirst()
umkehren lässt.
Wildcards
Sie können mehrere Sonderzeichen in der Maske verwenden:
*
– replaces any number of arbitrary characters (except/
)**
– ersetzt eine beliebige Anzahl von Zeichen einschließlich/
(d.h. es kann mehrstufig gesucht werden)?
– replaces one arbitrary character (except/
)[a-z]
– ersetzt ein Zeichen aus der Liste der Zeichen in eckigen Klammern[!a-z]
– ersetzt ein Zeichen außerhalb der Liste der Zeichen in eckigen Klammern
Beispiele für die Verwendung:
img/?.png
– Dateien mit dem Einbuchstabennamen0.png
,1.png
,x.png
, usw.logs/[0-9][0-9][0-9][0-9]-[01][0-9]-[0-3][0-9].log
– Protokolldateien im FormatYYYY-MM-DD
src/**/tests/*
– Dateien im Verzeichnissrc/tests
,src/foo/tests
,src/foo/bar/tests
und so weiter.docs/**.md
– alle Dateien mit der Erweiterung.md
in allen Unterverzeichnissen des Verzeichnissesdocs
Ausgenommen
Verwenden Sie die Methode exclude()
, um Dateien und Verzeichnisse von der Suche auszuschließen. Sie geben eine
Maske an, der die Datei nicht entsprechen darf. Beispiel für die Suche nach Dateien *.txt
mit Ausnahme derjenigen,
die den Buchstaben “X” im Namen enthalten:
Finder::findFiles('*.txt')
->exclude('*X*');
Verwenden Sie exclude()
, um durchsuchte Unterverzeichnisse zu überspringen:
Finder::findFiles('*.php')
->from($dir)
->exclude('temp', '.git')
Filtern von
Der Finder bietet mehrere Methoden, um die Ergebnisse zu filtern (d.h. zu reduzieren). Sie können sie kombinieren und wiederholt aufrufen.
Verwenden Sie size()
, um nach der Dateigröße zu filtern. Auf diese Weise finden wir Dateien mit Größen
zwischen 100 und 200 Byte:
Finder::findFiles('*.php')
->size('>=', 100)
->size('<=', 200);
Die Methode date()
filtert nach dem Datum, an dem die Datei zuletzt geändert wurde. Die Werte können absolut
oder relativ zum aktuellen Datum und zur aktuellen Uhrzeit angegeben werden, um z. B. Dateien zu finden, die in den letzten zwei
Wochen geändert wurden:
Finder::findFiles('*.php')
->date('>', '-2 weeks')
->from($dir)
Beide Funktionen verstehen die Operatoren >
, >=
, <
, <=
,
=
, !=
, <>
.
Der Finder erlaubt Ihnen auch, die Ergebnisse mit Hilfe von benutzerdefinierten Funktionen zu filtern. Die Funktion erhält ein
Nette\Utils\FileInfo
Objekt als Parameter und muss true
zurückgeben, um die Datei in die Ergebnisse
aufzunehmen.
Beispiel: Suche nach PHP-Dateien, die die Zeichenkette Nette
enthalten (Groß- und Kleinschreibung wird nicht
berücksichtigt):
Finder::findFiles('*.php')
->filter(fn($file) => strcasecmp($file->read(), 'Nette') === 0);
Tiefenfilterung
Bei der rekursiven Suche können Sie mit der Methode limitDepth()
die maximale Crawl-Tiefe festlegen. Wenn Sie
limitDepth(1)
einstellen, werden nur die ersten Unterverzeichnisse gecrawlt, limitDepth(0)
deaktiviert
das Crawlen in der Tiefe und ein Wert von –1 hebt die Begrenzung auf.
Der Finder erlaubt Ihnen, seine eigenen Funktionen zu verwenden, um zu entscheiden, welches Verzeichnis beim Durchsuchen
eingegeben werden soll. Die Funktion erhält ein Nette\Utils\FileInfo
Objekt als Parameter und muss true
zurückgeben, um das Verzeichnis zu betreten:
Finder::findFiles('*.php')
->descentFilter($file->getBasename() !== 'temp');
Sortieren
Der Finder bietet auch mehrere Funktionen zum Sortieren von Ergebnissen.
Die Methode sortByName()
sortiert die Ergebnisse nach Dateinamen. Die Sortierung ist natürlich, d.h. sie
behandelt die Zahlen in den Namen korrekt und gibt z.B. foo1.txt
vor foo10.txt
zurück.
Der Finder erlaubt Ihnen auch, mit einer eigenen Funktion zu sortieren. Sie nimmt zwei Nette\Utils\FileInfo
Objekte als Parameter und muss das Ergebnis des Vergleichs mit dem Operator <=>
zurückgeben, d.h.
-1
, 0
nebo 1
. So sortieren wir zum Beispiel Dateien nach Größe:
$finder->sortBy(fn($a, $b) => $a->getSize() <=> $b->getSize());
Mehrere verschiedene Suchvorgänge
Wenn Sie mehrere verschiedene Dateien an unterschiedlichen Orten oder nach unterschiedlichen Kriterien suchen müssen,
verwenden Sie die Methode append()
. Sie gibt ein neues Finder
Objekt zurück, so dass Sie
Methodenaufrufe verketten können:
($finder = new Finder) // speichert den ersten Finder in der Variable $finder!
->files('*.php') // Suche nach *.php Dateien in src/
->from('src')
->append()
->files('*.md') // in docs/ suchen Sie nach *.md-Dateien
->from('docs')
->append()
->files('*.json'); // im aktuellen Ordner wird nach *.json-Dateien gesucht
Alternativ können Sie auch die Methode append()
verwenden, um eine bestimmte Datei (oder ein Array von Dateien)
hinzuzufügen. Sie gibt dann das gleiche Objekt Finder
zurück:
$finder = Finder::findFiles('*.txt')
->append(__FILE__);
FileInfo
Nette\Utils\FileInfo ist eine Klasse, die eine Datei oder ein Verzeichnis in den Suchergebnissen darstellt. Sie ist eine Erweiterung der Klasse SplFileInfo, die Informationen wie Dateigröße, Datum der letzten Änderung, Name, Pfad usw. liefert.
Darüber hinaus bietet sie Methoden zur Rückgabe relativer Pfade, was bei der Suche in der Tiefe nützlich ist:
foreach (Finder::findFiles('*.jpg')->from('.') as $file) {
$absoluteFilePath = $file->getRealPath();
$relativeFilePath = $file->getRelativePathname();
}
Sie haben auch Methoden zum Lesen und Schreiben des Inhalts einer Datei:
foreach ($finder as $file) {
$contents = $file->read();
// ...
$file->write($contents);
}
Ergebnisse als Array zurückgeben
Wie in den Beispielen gesehen, implementiert der Finder die Schnittstelle IteratorAggregate
, so dass Sie
foreach
verwenden können, um die Ergebnisse zu durchsuchen. Er ist so programmiert, dass die Ergebnisse erst beim
Durchsuchen geladen werden. Wenn Sie also eine große Anzahl von Dateien haben, wartet er nicht darauf, dass alle gelesen
werden.
Sie können sich die Ergebnisse auch als Array von Nette\Utils\FileInfo
-Objekten zurückgeben lassen, indem Sie
die Methode collect()
verwenden. Das Array ist nicht assoziativ, sondern numerisch.
$array = $finder->findFiles('*.php')->collect();