Buscador: Búsqueda de archivos
¿Necesitas encontrar archivos que coincidan con una determinada máscara? El Finder puede ayudarte. Es una herramienta versátil y rápida para navegar por la estructura de directorios.
Se instala:
composer require nette/utils
Los ejemplos suponen que se ha creado un alias:
use Nette\Utils\Finder;
Utilizando
En primer lugar, vamos a ver cómo se puede utilizar Nette\Utils\Finder para listar los nombres de archivo con
las extensiones .txt
y .md
en el directorio actual:
foreach (Finder::findFiles(['*.txt', '*.md']) as $name => $file) {
echo $file;
}
El directorio por defecto para la búsqueda es el directorio actual, pero puedes cambiarlo usando los métodos in() o from(). La variable $file
es una instancia de la clase FileInfo con muchos métodos útiles. La clave $name
contiene la ruta al archivo como una
cadena.
¿Qué buscar?
Además del método findFiles()
, también existe findDirectories()
, que busca sólo en directorios, y
find()
, que busca en ambos. Estos métodos son estáticos, por lo que pueden invocarse sin crear una instancia. El
parámetro máscara es opcional, si no se especifica, se busca en todo.
foreach (Finder::find() as $file) {
echo $file; // ahora todos los archivos y directorios están listados
}
Utilice los métodos files()
y directories()
para añadir qué más buscar. Los métodos se pueden
llamar repetidamente y se puede proporcionar una matriz de máscaras como parámetro:
Finder::findDirectories('vendor') // todos los directorios
->files(['*.php', '*.phpt']); // además de todos los archivos PHP
Una alternativa a los métodos estáticos es crear una instancia utilizando new Finder
(el objeto fresco creado de
esta manera no busca nada) y especificar qué buscar utilizando files()
y directories()
:
(new Finder)
->directories() // todos los directorios
->files('*.php'); // además de todos los ficheros PHP
Puede utilizar comodines *
, **
, ?
and [...]
en
la máscara. Incluso puede especificar en directorios, por ejemplo src/*.php
buscará todos los archivos PHP en el
directorio src
.
Los enlaces simbólicos también se consideran directorios o archivos.
¿Dónde buscar?
El directorio de búsqueda por defecto es el directorio actual. Puede cambiarlo utilizando los métodos in()
y
from()
. Como puedes ver por los nombres de los métodos, in()
busca sólo en el directorio actual,
mientras que from()
busca también en sus subdirectorios (recursivamente). Si desea buscar recursivamente en el
directorio actual, puede utilizar from('.')
.
Estos métodos se pueden llamar varias veces o se les pueden pasar varias rutas como matrices, entonces se buscará en todos
los directorios. Si uno de los directorios no existe, se lanza un Nette\UnexpectedValueException
.
Finder::findFiles('*.php')
->in(['src', 'tests']) // busca directamente en src/ y tests/
->from('vendor'); // busca también en vendor/ subdirectorios
Las rutas relativas son relativas al directorio actual. Por supuesto, también se pueden especificar rutas absolutas:
Finder::findFiles('*.php')
->in('/var/www/html');
Wildcards comodines *
, **
, ?
can be used in the path. For
example, you can use the path src/*/*.php
para buscar todos los archivos PHP en los directorios de segundo nivel en
el directorio src
. El carácter **
, llamado globstar, es una poderosa carta de triunfo porque permite
buscar también en subdirectorios: use src/**/tests/*.php
para buscar todos los archivos PHP en el directorio
tests
ubicados en src
o cualquiera de sus subdirectorios.
Por otro lado, los caracteres comodín [...]
no están soportados en la ruta, es decir, no tienen un significado
especial para evitar comportamientos no deseados en caso de que busque por ejemplo in(__DIR__)
y por casualidad
aparezcan caracteres []
en la ruta.
Al buscar archivos y directorios en profundidad, se devuelve primero el directorio padre y luego los archivos que contiene, lo
que puede invertirse con childFirst()
.
Comodines
Puede utilizar varios caracteres especiales en la máscara:
*
– replaces any number of arbitrary characters (except/
)**
– sustituye a cualquier número de caracteres arbitrarios, incluido/
(es decir, puede buscarse en varios niveles)?
– replaces one arbitrary character (except/
)[a-z]
– sustituye un carácter de la lista de caracteres entre corchetes[!a-z]
– sustituye un carácter fuera de la lista de caracteres entre corchetes
Ejemplos de utilización:
img/?.png
– archivos con el nombre de una sola letra0.png
,1.png
,x.png
, etc.logs/[0-9][0-9][0-9][0-9]-[01][0-9]-[0-3][0-9].log
– archivos de registro con el formatoYYYY-MM-DD
src/**/tests/*
– ficheros en el directoriosrc/tests
,src/foo/tests
,src/foo/bar/tests
etc.docs/**.md
– todos los archivos con la extensión.md
en todos los subdirectorios del directoriodocs
Excluyendo
Utilice el método exclude()
para excluir archivos y directorios de las búsquedas. Se especifica una máscara con
la que el fichero no debe coincidir. Ejemplo de búsqueda de archivos *.txt
excepto los que contienen la letra
X
en el nombre:
Finder::findFiles('*.txt')
->exclude('*X*');
Utilice exclude()
para omitir los subdirectorios buscados:
Finder::findFiles('*.php')
->from($dir)
->exclude('temp', '.git')
Filtrado
El Finder ofrece varios métodos para filtrar los resultados (es decir, reducirlos). Puede combinarlos y llamarlos repetidamente.
Utilice size()
para filtrar por tamaño de archivo. De este modo, encontraremos los ficheros con tamaños
comprendidos entre 100 y 200 bytes:
Finder::findFiles('*.php')
->size('>=', 100)
->size('<=', 200);
El método date()
filtra por la fecha de la última modificación del fichero. Los valores pueden ser absolutos
o relativos a la fecha y hora actuales, por ejemplo, así se encuentran los ficheros modificados en las dos últimas semanas:
Finder::findFiles('*.php')
->date('>', '-2 weeks')
->from($dir)
Ambas funciones entienden los operadores >
, >=
, <
, <=
,
=
, !=
, <>
.
El Finder también permite filtrar los resultados mediante funciones personalizadas. La función recibe un objeto
Nette\Utils\FileInfo
como parámetro y debe devolver true
para incluir el archivo en los resultados.
Ejemplo: buscar archivos PHP que contengan la cadena Nette
(sin distinguir mayúsculas de minúsculas):
Finder::findFiles('*.php')
->filter(fn($file) => strcasecmp($file->read(), 'Nette') === 0);
Filtrado en profundidad
Al realizar búsquedas recursivas, puedes establecer la profundidad máxima de rastreo utilizando el método
limitDepth()
. Si establece limitDepth(1)
, sólo se rastrean los primeros subdirectorios,
limitDepth(0)
desactiva el rastreo en profundidad y un valor de –1 anula el límite.
El Finder permite utilizar sus propias funciones para decidir en qué directorio se entra al navegar. La función recibe un
objeto Nette\Utils\FileInfo
como parámetro y debe devolver true
para entrar en el directorio:
Finder::findFiles('*.php')
->descentFilter($file->getBasename() !== 'temp');
Ordenar
El Buscador también ofrece varias funciones para ordenar los resultados.
El método sortByName()
ordena los resultados por nombre de archivo. La ordenación es natural, es decir, maneja
correctamente los números de los nombres y devuelve, por ejemplo, foo1.txt
antes que foo10.txt
.
El Finder también permite ordenar utilizando una función personalizada. Toma dos objetos Nette\Utils\FileInfo
como parámetros y debe devolver el resultado de la comparación con el operador <=>
es decir, -1
,
0
nebo 1
. Por ejemplo, así es como se ordenan los archivos por tamaño:
$finder->sortBy(fn($a, $b) => $a->getSize() <=> $b->getSize());
Múltiples búsquedas diferentes
Si necesita encontrar varios archivos diferentes en distintas ubicaciones o que cumplan distintos criterios, utilice el
método append()
. Devuelve un nuevo objeto Finder
para que pueda encadenar llamadas a métodos:
($finder = new Finder) // ¡almacena el primer Finder en la variable $finder!
->files('*.php') // busca archivos *.php en src/
->from('src')
->append()
->files('*.md') // en docs/ busca archivos *.md
->from('docs')
->append()
->files('*.json'); // en la carpeta actual busca archivos *.json
Alternativamente, puede utilizar el método append()
para añadir un archivo específico (o una matriz de
archivos). Entonces devuelve el mismo objeto Finder
:
$finder = Finder::findFiles('*.txt')
->append(__FILE__);
FileInfo
Nette\Utils\FileInfo es una clase que representa un fichero o directorio en los resultados de búsqueda. Es una extensión de la clase SplFileInfo que proporciona información como el tamaño del fichero, fecha de última modificación, nombre, ruta, etc.
Además, proporciona métodos para devolver rutas relativas, lo cual es útil cuando se navega en profundidad:
foreach (Finder::findFiles('*.jpg')->from('.') as $file) {
$absoluteFilePath = $file->getRealPath();
$relativeFilePath = $file->getRelativePathname();
}
También dispone de métodos para leer y escribir el contenido de un fichero:
foreach ($buscador como $archivo) {
$contenidos = $file->read();
// ...
$file->write($contents);
}
Devolución de resultados como array
Como se ha visto en los ejemplos, el Finder implementa la interfaz IteratorAggregate
, así que puedes usar
foreach
para navegar por los resultados. Está programado para que los resultados sólo se carguen mientras navegas,
así que si tienes un gran número de archivos, no espera a que se lean todos.
También puede obtener los resultados como una matriz de objetos Nette\Utils\FileInfo
, utilizando el método
collect()
. La matriz no es asociativa, sino numérica.
$array = $finder->findFiles('*.php')->collect();