Finder: Ricerca di file
Avete bisogno di trovare i file che corrispondono a una determinata maschera? Il Finder può aiutarvi. È uno strumento versatile e veloce per navigare nella struttura delle directory.
Installazione:
composer require nette/utils
Gli esempi presuppongono la creazione di un alias:
use Nette\Utils\Finder;
Utilizzando
Per prima cosa, vediamo come utilizzare Nette\Utils\Finder per elencare i nomi dei file con estensione
.txt
e .md
nella directory corrente:
foreach (Finder::findFiles(['*.txt', '*.md']) as $name => $file) {
echo $file;
}
La directory predefinita per la ricerca è quella corrente, ma è possibile cambiarla utilizzando i metodi in() o from(). La variabile $file
è un'istanza della classe FileInfo con molti metodi utili. La chiave $name
contiene il percorso del file come
stringa.
Cosa cercare?
Oltre al metodo findFiles()
, esistono anche findDirectories()
, che cerca solo nelle directory, e
find()
, che cerca in entrambe. Questi metodi sono statici, quindi possono essere richiamati senza creare un'istanza.
Il parametro mask è opzionale; se non viene specificato, viene cercato tutto.
foreach (Finder::find() as $file) {
echo $file; // ora tutti i file e le directory sono elencati
}
Si possono usare i metodi files()
e directories()
per aggiungere altri elementi da ricercare.
I metodi possono essere richiamati ripetutamente e si può fornire 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 con new Finder
(l'oggetto fresco creato in questo modo non
cerca nulla) e specificare cosa cercare con files()
e directories()
:
(new Finder)
->directories() // tutte le directory
->files('*.php'); // più tutti i file PHP
Si possono usare i caratteri jolly *
, **
, ?
and
[...]
nella maschera. Si possono anche specificare le directory, ad esempio src/*.php
cercherà tutti
i file PHP nella directory src
.
Anche i collegamenti simbolici sono considerati directory o file.
Dove cercare?
La directory di ricerca predefinita è la directory corrente. È possibile modificarla utilizzando i metodi in()
e from()
. Come si può vedere dai nomi dei metodi, in()
cerca solo nella directory corrente, mentre
from()
cerca anche nelle sue sottodirectory (in modo ricorsivo). Se si desidera effettuare una ricerca ricorsiva
nella directory corrente, si può usare from('.')
.
Questi metodi possono essere richiamati più volte o si possono passare percorsi multipli come array; i file verranno cercati
in tutte le directory. Se una delle directory non esiste, viene lanciato 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, possono essere specificati anche percorsi assoluti:
Finder::findFiles('*.php')
->in('/var/www/html');
Caratteri jolly *
, **
, ?
can be used in the path. For
example, you can use the path src/*/*.php
per cercare tutti i file PHP nelle directory di secondo livello della
directory src
. Il carattere **
, chiamato globstar, è un potente asso nella manica perché permette di
cercare anche nelle sottodirectory: usare src/**/tests/*.php
per cercare tutti i file PHP nella directory
tests
che si trovano in src
o in una qualsiasi delle sue sottodirectory.
D'altra parte, 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 per caso appaia il
carattere []
nel percorso.
Quando si effettua una ricerca approfondita di file e directory, viene restituita prima la directory madre e poi i file in
essa contenuti, cosa che può essere invertita con childFirst()
.
I caratteri jolly
È possibile utilizzare diversi caratteri speciali nella maschera:
*
– replaces any number of arbitrary characters (except/
)**
– sostituisce un numero qualsiasi di caratteri arbitrari, incluso/
(cioè può essere ricercato a più livelli)?
– replaces one arbitrary character (except/
)[a-z]
– sostituisce un carattere dall'elenco di caratteri tra parentesi quadre[!a-z]
– sostituisce un carattere al di fuori dell'elenco di caratteri tra parentesi quadre
Esempi di utilizzo:
img/?.png
– file con il 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
– file di 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 l'estensione.md
in tutte le sottodirectory della directorydocs
Escluso
Utilizzate il metodo exclude()
per escludere file e directory dalle ricerche. Si specifica una maschera a cui il
file non deve corrispondere. Esempio di ricerca dei file *.txt
tranne quelli contenenti la lettera X
nel nome:
Finder::findFiles('*.txt')
->exclude('*X*');
Utilizzare exclude()
per saltare le sottodirectory sfogliate:
Finder::findFiles('*.php')
->from($dir)
->exclude('temp', '.git')
Filtraggio
Il Finder offre diversi metodi per filtrare i risultati (cioè per ridurli). È possibile combinarli e richiamarli ripetutamente.
Utilizzate size()
per filtrare in base alla dimensione del file. In questo modo si trovano i file con dimensioni
comprese tra 100 e 200 byte:
Finder::findFiles('*.php')
->size('>=', 100)
->size('<=', 200);
Il metodo date()
filtra in base alla data dell'ultima modifica del file. I valori possono essere assoluti
o relativi alla data e all'ora corrente, ad esempio per trovare i file modificati nelle ultime due settimane:
Finder::findFiles('*.php')
->date('>', '-2 weeks')
->from($dir)
Entrambe le funzioni comprendono gli operatori >
, >=
, <
, <=
,
=
, !=
, <>
.
Il Finder consente anche di filtrare i risultati utilizzando funzioni personalizzate. La funzione riceve un oggetto
Nette\Utils\FileInfo
come parametro e deve restituire true
per includere il file nei risultati.
Esempio: ricerca dei file PHP che contengono la stringa Nette
(senza distinzione tra maiuscole e minuscole):
Finder::findFiles('*.php')
->filter(fn($file) => strcasecmp($file->read(), 'Nette') === 0);
Filtro di profondità
Quando si effettua una ricerca ricorsiva, è possibile impostare la profondità massima di crawling utilizzando il metodo
limitDepth()
. Se si imposta limitDepth(1)
, vengono strisciate solo le prime sottodirectory,
limitDepth(0)
disabilita il crawling di profondità e un valore di –1 annulla il limite.
Il Finder consente di utilizzare le proprie funzioni per decidere quale directory inserire durante la navigazione. La funzione
riceve un oggetto Nette\Utils\FileInfo
come parametro e deve restituire true
per entrare nella
directory:
Finder::findFiles('*.php')
->descentFilter($file->getBasename() !== 'temp');
Ordinamento
Il Finder offre anche diverse funzioni per ordinare i risultati.
Il metodo sortByName()
ordina i risultati in base al nome del file. L'ordinamento è naturale, cioè gestisce
correttamente i numeri nei nomi e restituisce, ad esempio, foo1.txt
prima di foo10.txt
.
Il Finder consente anche di ordinare utilizzando una funzione personalizzata. Essa prende come parametri due oggetti
Nette\Utils\FileInfo
e deve restituire il risultato del confronto con l'operatore <=>
cioè
-1
, 0
nebo 1
. Ad esempio, ecco come ordinare i file in base alle dimensioni:
$finder->sortBy(fn($a, $b) => $a->getSize() <=> $b->getSize());
Ricerche multiple diverse
Se è necessario trovare più file diversi in posizioni diverse o che soddisfano criteri diversi, utilizzare il metodo
append()
. Esso restituisce un nuovo oggetto Finder
, in modo da poter concatenare le chiamate ai
metodi:
($finder = new Finder) // memorizza il primo Finder nella variabile $finder!
->files('*.php') // cerca i file *.php in src/
->from('src')
->append()
->files('*.md') // in docs/ cerca i file *.md
->from('docs')
->append()
->files('*.json'); // nella cartella corrente cerca i file *.json
In alternativa, si può usare il metodo append()
per aggiungere un file specifico (o un array di file). In tal
caso, viene restituito 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 quali la dimensione del file, la data dell'ultima modifica, il nome, il percorso, ecc.
Inoltre, fornisce metodi per la restituzione di percorsi relativi, utili quando si naviga in profondità:
foreach (Finder::findFiles('*.jpg')->from('.') as $file) {
$absoluteFilePath = $file->getRealPath();
$relativeFilePath = $file->getRelativePathname();
}
Sono disponibili anche metodi per leggere e scrivere il contenuto di un file:
foreach ($finder as $file) {
$contents = $file->read();
// ...
$file->write($contents);
}
Restituzione dei risultati come array
Come si è visto negli esempi, il Finder implementa l'interfaccia IteratorAggregate
, quindi si può usare
foreach
per sfogliare i risultati. È programmato in modo che i risultati vengano caricati solo durante la
navigazione, quindi se si ha un gran numero di file, non si aspetta che vengano letti tutti.
I risultati possono anche essere restituiti come un array di oggetti Nette\Utils\FileInfo
, usando il metodo
collect()
. L'array non è associativo, ma numerico.
$array = $finder->findFiles('*.php')->collect();