Finder: ricerca di file
Hai bisogno di trovare file che corrispondano a una certa maschera? Finder ti aiuterà in questo. È uno strumento versatile e veloce per attraversare la struttura delle directory.
Installazione:
composer require nette/utils
Gli esempi presuppongono la creazione di un alias:
use Nette\Utils\Finder;
Utilizzo
Innanzitutto, vediamo come puoi usare Nette\Utils\Finder per elencare i nomi dei file con
estensioni .txt
e .md
nella directory corrente:
foreach (Finder::findFiles(['*.txt', '*.md']) as $name => $file) {
echo $file;
}
La directory predefinita per la ricerca è la directory corrente, ma puoi cambiarla usando i metodi in() o from(). La variabile $file
è un'istanza della classe FileInfo con molti metodi utili. Nella chiave $name
c'è il percorso del file come
stringa.
Cosa cercare?
Oltre al metodo findFiles()
, c'è anche findDirectories()
, che cerca solo directory, e
find()
, che cerca entrambi. Questi metodi sono statici, quindi possono essere chiamati senza creare un'istanza. Il
parametro con la maschera è opzionale; se non lo specifichi, verrà cercato tutto.
foreach (Finder::find() as $file) {
echo $file; // ora verranno stampati tutti i file e le directory
}
Usando i metodi files()
e directories()
, puoi specificare cos'altro cercare. I metodi possono
essere chiamati ripetutamente e puoi anche specificare un array di maschere come parametro:
Finder::findDirectories('vendor') // tutte le directory
->files(['*.php', '*.phpt']); // più tutti i file PHP
Un'alternativa ai metodi statici è creare un'istanza usando new Finder
(un oggetto appena creato in questo modo
non cerca nulla) e specificare cosa cercare usando files()
e directories()
:
(new Finder)
->directories() // tutte le directory
->files('*.php'); // più tutti i file PHP
Nella maschera puoi usare i caratteri jolly *
, **
, ?
e [...]
. Puoi persino specificare directory, ad esempio src/*.php
cercherà tutti i file PHP nella
directory src
.
Anche i link simbolici sono considerati directory o file.
Dove cercare?
La directory predefinita per la ricerca è la directory corrente. Puoi cambiarla usando i metodi in()
e
from()
. Come suggeriscono i nomi dei metodi, in()
cerca solo nella directory specificata, mentre
from()
cerca anche nelle sue sottodirectory (ricorsivamente). Se vuoi cercare ricorsivamente nella directory
corrente, puoi usare from('.')
.
Questi metodi possono essere chiamati più volte o puoi passare loro più percorsi come array; i file verranno quindi cercati
in tutte le directory. Se una delle directory non esiste, verrà lanciata un'eccezione
Nette\UnexpectedValueException
.
Finder::findFiles('*.php')
->in(['src', 'tests']) // cerca direttamente in src/ e tests/
->from('vendor'); // cerca anche nelle sottodirectory di vendor/
I percorsi relativi sono relativi alla directory corrente. Naturalmente, è possibile specificare anche percorsi assoluti:
Finder::findFiles('*.php')
->in('/var/www/html');
È possibile utilizzare i caratteri jolly caratteri jolly *
, **
,
?
nel percorso. Ad esempio, puoi usare il percorso src/*/*.php
per cercare tutti i file PHP nelle
directory di secondo livello nella directory src
. Il carattere **
, chiamato globstar, è un potente asso
nella manica perché permette di cercare anche nelle sottodirectory: usando src/**/tests/*.php
cerchi tutti i file
PHP nella directory tests
situata in src
o in una qualsiasi delle sue sottodirectory.
Al contrario, i caratteri jolly [...]
non sono supportati nel percorso, cioè non hanno un significato speciale,
per evitare comportamenti indesiderati nel caso in cui si cerchi, ad esempio, in(__DIR__)
e casualmente nel percorso
compaiano i caratteri []
.
Durante la ricerca approfondita di file e directory, viene restituita prima la directory padre e solo dopo i file in essa
contenuti, il che può essere invertito usando childFirst()
.
Caratteri jolly
Nella maschera puoi usare diversi caratteri speciali:
*
– sostituisce un numero qualsiasi di caratteri qualsiasi (eccetto/
)**
– sostituisce un numero qualsiasi di caratteri qualsiasi incluso/
(cioè è possibile cercare a più livelli)?
– sostituisce un carattere qualsiasi (eccetto/
)[a-z]
– sostituisce un carattere dall'elenco di caratteri tra parentesi quadre[!a-z]
– sostituisce un carattere non presente nell'elenco di caratteri tra parentesi quadre
Esempi di utilizzo:
img/?.png
– file con un nome di una sola lettera0.png
,1.png
,x.png
, ecc.logs/[0-9][0-9][0-9][0-9]-[01][0-9]-[0-3][0-9].log
– log nel formatoYYYY-MM-DD
src/**/tests/*
– file nella directorysrc/tests
,src/foo/tests
,src/foo/bar/tests
e così via.docs/**.md
– tutti i file con estensione.md
in tutte le sottodirectory della directorydocs
Esclusione
Usando il metodo exclude()
, è possibile escludere file e directory dalla ricerca. Specifichi una maschera a cui
il file non deve corrispondere. Esempio di ricerca di file *.txt
eccetto quelli che contengono la lettera
X
nel nome:
Finder::findFiles('*.txt')
->exclude('*X*');
Per saltare le sottodirectory attraversate, usa exclude()
:
Finder::findFiles('*.php')
->from($dir)
->exclude('temp', '.git')
Filtraggio
Finder offre diversi metodi per filtrare i risultati (cioè ridurli). Puoi combinarli e chiamarli ripetutamente.
Usando size()
, filtriamo per dimensione del file. In questo modo troviamo file con dimensioni comprese tra 100 e
200 byte:
Finder::findFiles('*.php')
->size('>=', 100)
->size('<=', 200);
Il metodo date()
filtra per data dell'ultima modifica del file. I valori possono essere assoluti o relativi alla
data e all'ora correnti; ad esempio, in questo modo troviamo i file modificati nelle ultime due settimane:
Finder::findFiles('*.php')
->date('>', '-2 weeks')
->from($dir)
Entrambe le funzioni comprendono gli operatori >
, >=
, <
, <=
,
=
, !=
, <>
.
Finder permette anche di filtrare i risultati usando funzioni personalizzate. La funzione riceve come parametro un oggetto
Nette\Utils\FileInfo
e deve restituire true
affinché il file sia incluso nei risultati.
Esempio: ricerca di file PHP che contengono la stringa Nette
(indipendentemente dalle maiuscole/minuscole):
Finder::findFiles('*.php')
->filter(fn($file) => strcasecmp($file->read(), 'Nette') === 0);
Filtraggio in profondità
Durante la ricerca ricorsiva, puoi impostare la profondità massima di attraversamento usando il metodo
limitDepth()
. Se imposti limitDepth(1)
, vengono attraversate solo le prime sottodirectory,
limitDepth(0)
disattiva l'attraversamento in profondità e il valore –1 annulla il limite.
Finder permette di decidere in quale directory entrare durante l'attraversamento usando funzioni personalizzate. La funzione
riceve come parametro un oggetto Nette\Utils\FileInfo
e deve restituire true
per entrare nella
directory:
Finder::findFiles('*.php')
->descentFilter($file->getBasename() !== 'temp');
Ordinamento
Finder offre anche diverse funzioni per ordinare i risultati.
Il metodo sortByName()
ordina i risultati per nome del file. L'ordinamento è naturale, quindi gestisce
correttamente i numeri nei nomi e restituisce, ad esempio, foo1.txt
prima di foo10.txt
.
Finder permette anche di ordinare usando una funzione personalizzata. Questa riceve come parametri due oggetti
Nette\Utils\FileInfo
e deve restituire il risultato del confronto con l'operatore <=>
, cioè
-1
, 0
o 1
. Ad esempio, in questo modo ordiniamo i file per dimensione:
$finder->sortBy(fn($a, $b) => $a->getSize() <=> $b->getSize());
Ricerche multiple diverse
Se hai bisogno di trovare più file diversi in posizioni diverse o che soddisfano criteri diversi, usa il metodo
append()
. Restituisce un nuovo oggetto Finder
, quindi è possibile concatenare le chiamate ai
metodi:
($finder = new Finder) // salviamo il primo Finder nella variabile $finder!
->files('*.php') // in src/ cerchiamo file *.php
->from('src')
->append()
->files('*.md') // in docs/ cerchiamo file *.md
->from('docs')
->append()
->files('*.json'); // nella cartella corrente cerchiamo file *.json
In alternativa, è possibile utilizzare il metodo append()
per aggiungere un file specifico (o un array di file).
Quindi restituisce lo stesso oggetto Finder
:
$finder = Finder::findFiles('*.txt')
->append(__FILE__);
FileInfo
Nette\Utils\FileInfo è una classe che rappresenta un file o una directory nei risultati della ricerca. È un'estensione della classe SplFileInfo, che fornisce informazioni come la dimensione del file, la data dell'ultima modifica, il nome, il percorso, ecc.
Inoltre, fornisce metodi per restituire il percorso relativo, il che è utile durante l'attraversamento in profondità:
foreach (Finder::findFiles('*.jpg')->from('.') as $file) {
$absoluteFilePath = $file->getRealPath();
$relativeFilePath = $file->getRelativePathname();
}
Inoltre, hai a disposizione metodi per leggere e scrivere il contenuto del file:
foreach ($finder as $file) {
$contents = $file->read();
// ...
$file->write($contents);
}
Restituzione dei risultati come array
Come visto negli esempi, Finder implementa l'interfaccia IteratorAggregate
, quindi puoi usare foreach
per scorrere i risultati. È programmato in modo che i risultati vengano caricati solo durante l'iterazione, quindi se hai un
gran numero di file, non si aspetta che vengano letti tutti.
Puoi anche farti restituire i risultati come un array di oggetti Nette\Utils\FileInfo
, usando il metodo
collect()
. L'array non è associativo, ma numerico.
$array = $finder->findFiles('*.php')->collect();