¿Qué razones existen para preferir glob sobre readdir(o viceversa) en Perl?
(10)
Pros globales:
3) No es necesario anteponer el nombre del directorio a los elementos manualmente
Excepción:
say for glob "*";
--output:--
1perl.pl
2perl.pl
2perl.pl.bak
3perl.pl
3perl.pl.bak
4perl.pl
data.txt
data1.txt
data2.txt
data2.txt.out
Por lo que puedo decir, la regla para glob
es: debe proporcionar una ruta completa al directorio para obtener caminos completos hacia atrás. Los documentos de Perl no parecen mencionar eso, y ninguno de los mensajes aquí.
Esto significa que se puede usar glob
en lugar de readdir
cuando solo desea nombres de archivo (en lugar de rutas completas), y no desea que se devuelvan archivos ocultos, es decir, aquellos que comienzan con ''.''. Por ejemplo,
chdir ("../..");
say for glob("*");
Esta pregunta es un spin-off de este . Algo de historia: cuando aprendí Perl por primera vez, casi siempre usaba glob
lugar de opendir
+ readdir
porque me resultaba más fácil. Luego, más tarde, varios mensajes y lecturas sugirieron que glob
era malo, por lo que ahora casi siempre uso readdir
.
Después de pensar en esta pregunta reciente, me di cuenta de que mis razones para una u otra opción pueden ser litera. Por lo tanto, voy a exponer algunos pros y contras, y espero que la gente más experimentada de Perl pueda intervenir y aclarar. La pregunta en pocas palabras es ¿existen razones de peso para preferir glob
a readdir
o readdir
a glob
(en algunos o todos los casos)?
Pros glob
:
- No hay archivos de puntos (a menos que los solicite)
- El orden de los artículos está garantizado
- No es necesario anteponer el nombre del directorio a los elementos manualmente
- Mejor nombre (c''mon -
glob
versusreaddir
no es competencia si estamos juzgando solo por nombres) (A partir de la respuesta de ysth; cf.
glob
cons 4 a continuación) Puede devolver nombres de archivo inexistentes:@deck = glob "{A,K,Q,J,10,9,8,7,6,5,4,3,2}{/x{2660},/x{2665},/x{2666},/x{2663}}";
contras glob
:
- Las versiones antiguas simplemente están rotas (pero ''más antiguo'' significa pre 5.6, creo, y francamente si estás usando 5.6 Perl anterior, tienes problemas mayores)
- Llamada
stat
cada vez (es decir, uso inútil destat
en la mayoría de los casos). - Problemas con espacios en nombres de directorio (¿esto sigue siendo cierto?)
(De la respuesta de Brian) Puede devolver nombres de archivo que no existen:
$ perl -le ''print glob "{ab}{cd}"''
readdir
pros:
- (De la respuesta de
opendir
)opendir
devuelve unopendir
que puede pasar en su programa (y reutilizar), peroglob
simplemente devuelve una lista - (De la respuesta de
readdir
)readdir
es un iterador apropiado y proporciona funciones pararewinddir
,seekdir
,telldir
- ¿Más rápido? (Conjetura pura basada en algunas de las características de
glob
de arriba. No estoy realmente preocupado por este nivel de optimización de todos modos, pero es un profesional teórico). - ¿Menos propenso a los errores de borde que a
glob
? - Lee todo (archivos de puntos también) de manera predeterminada (esto también es una estafa)
- Puede convencerlo de que no nombre un archivo
0
(una estafa también - vea la respuesta de Brad) - ¿Nadie? Bueller? Bueller?
readdir
contras:
- Si no recuerda agregar el nombre del directorio, recibirá un bit cuando intente realizar pruebas de archivos o copiar elementos o editar elementos o ...
- Si no recuerdas agotar el
.
y..
elementos, obtendrá un poco cuando cuente elementos, o intente caminar recursivamente por el árbol de archivos o ... - ¿Mencioné anteponer el nombre del directorio? (Una nota al margen, pero mi primera publicación en la lista de correo de Perl para principiantes fue el clásico "¿Por qué este código que involucra pruebas de archivos no funciona alguna vez?" Relacionado con este problema. Aparentemente, todavía estoy amargado).
- Los artículos son devueltos sin un orden en particular. Esto significa que a menudo tendrá que recordar ordenarlos de alguna manera. (Esto podría ser un profesional si significa más velocidad, y si eso significa que realmente piensa en cómo y si necesita ordenar elementos). Editar : Muestra pequeña y
readdir
, pero en unreaddir
Mac devuelve los elementos en orden alfabético, sin distinción entre mayúsculas y minúsculas. . En una caja Debian y un servidor OpenBSD, el orden es completamente aleatorio. Probé la Mac con el Perl integrado de Apple (5.8.8) y mi propio compilado 5.10.1. El cuadro de Debian es 5.10.0, al igual que el equipo de OpenBSD. Me pregunto si esto es un problema del sistema de archivos, en lugar de Perl. - Lee todo (archivos duales también) de forma predeterminada (esto también es un profesional)
- No necesariamente funciona bien con un archivo llamado
0
(ver pros también - ver la respuesta de Brad)
Aquí hay una desventaja para opendir
y readdir
.
{
open my $file, ''>'', 0;
print {$file} ''Breaks while( readdir ){ ... }''
}
opendir my $dir, ''.'';
my $a = 0;
++$a for readdir $dir;
print $a, "/n";
rewinddir $dir;
my $b = 0;
++$b while readdir $dir;
print $b, "/n";
Es de esperar que ese código imprima el mismo número dos veces, pero no porque haya un archivo con el nombre 0
. En mi computadora imprime 251
y 188
, probado con Perl v5.10.0 y v5.10.1
Este problema también hace que esto solo imprima un montón de líneas vacías, independientemente de la existencia del archivo 0
:
use 5.10.0;
opendir my $dir, ''.'';
say while readdir $dir;
Donde como esto siempre funciona bien:
use 5.10.0;
my $a = 0;
++$a for glob ''*'';
say $a;
my $b = 0;
++$b while glob ''*'';
say $b;
say for glob ''*'';
say while glob ''*'';
Repare estos problemas y envié un parche que lo convirtió en Perl v5.11.2, por lo que funcionará correctamente con Perl v5.12.0 cuando se publique.
Mi solución convierte esto:
while( readdir $dir ){ ... }
dentro de esto:
while( defined( $_ = readdir $dir ){ ...}
Lo que hace que funcione de la misma manera que la read
ha trabajado en los archivos. En realidad, es el mismo fragmento de código, acabo de agregar otro elemento a las sentencias if
correspondientes.
Bueno, prácticamente lo cubres. Teniendo esto en cuenta, tendería a usar glob
cuando glob
un guión único y rápido y su comportamiento es justo lo que quiero, y use opendir
y readdir
en el código de producción en curso o en las bibliotecas donde puedo tomarme mi tiempo y un código más claro y limpio es útil.
En una nota similar, File::Slurp
tiene una función llamada read_dir
.
Como utilizo mucho las otras funciones de File::Slurp
en mis scripts, read_dir
también se ha convertido en un hábito.
También tiene las siguientes opciones: err_mode
, prefix
y keep_dot_dot
.
Esa fue una lista bastante completa. readdir
(y readdir
+ grep
) tiene menos sobrecarga que glob
por lo que es una ventaja para readdir
si necesita analizar muchos directorios.
Para cosas pequeñas y simples, prefiero glob
. Justo el otro día, lo usé y una secuencia de comandos de veinte líneas de Perl para volver a grabar una gran parte de mi biblioteca de música. glob
, sin embargo, tiene un nombre bastante extraño. Glob? No es para nada intuitivo, por lo que se refiere a un nombre.
Mi mayor problema con readdir
es que trata un directorio de una manera extraña para la mayoría de las personas. Por lo general, los programadores no piensan en un directorio como un flujo, lo consideran un recurso, o una lista, lo que proporciona glob. El nombre es mejor, la funcionalidad es mejor, pero la interfaz aún deja algo que desear.
Primero, lee un poco. Capítulo 9.6. de Perl Cookbook describe el punto que quiero llegar muy bien, justo debajo del encabezado de la discusión.
En segundo lugar, haga una búsqueda de glob
y dosglob
en su directorio de Perl. Si bien se pueden usar muchas fuentes diferentes (formas de obtener la lista de archivos), la razón por la que le dosglob
es que si está en una plataforma Windows (y usa la solución dosglob
), en realidad está usando opendir
/ readdir
/ closedir
. Otras versiones usan comandos de shell incorporados o ejecutables precompilados específicos del sistema operativo.
Si sabe que se dirige a una plataforma específica, puede usar esta información para su beneficio. Solo como referencia, analicé esto en Strawberry Perl Portable edition 5.12.2, por lo que las cosas pueden ser ligeramente diferentes en versiones más nuevas o originales de Perl.
Te perdiste la diferencia más grande y más importante entre ellos: glob
te devuelve una lista, pero opendir
te da un identificador de directorio. Puede pasar ese control de directorio para permitir que otros objetos o subrutinas lo usen. Con el identificador de directorio, la subrutina u objeto no tiene que saber nada acerca de su origen, quién más lo está usando, y así sucesivamente:
sub use_any_dir_handle {
my( $dh ) = @_;
rewinddir $dh;
...do some filtering...
return /@files;
}
Con el manejador de dir, tienes un iterador controlable donde puedes moverte con seekdir
, aunque con glob
simplemente obtienes el siguiente elemento.
Sin embargo, al igual que con cualquier cosa, los costos y beneficios solo tienen sentido cuando se aplican a un contexto determinado. No existen fuera de un uso particular. Tienes una excelente lista de sus diferencias, pero no clasificaría esas diferencias sin saber lo que intentabas hacer con ellas.
Algunas otras cosas para recordar:
Puedes implementar tu propio glob con
opendir
, pero no al revés.glob usa su propia sintaxis comodín, y eso es todo lo que obtienes.
glob puede devolver nombres de archivos que no existen:
$ perl -le ''print glob "{ab}{cd}"''
global pros: puede devolver ''nombres de archivo'' que no existen:
my @deck = List::Util::shuffle glob "{A,K,Q,J,10,9,8,7,6,5,4,3,2}{/x{2660},/x{2665},/x{2666},/x{2663}}";
while (my @hand = splice @deck,0,13) {
say join ",", @hand;
}
__END__
6♥,8♠,7♠,Q♠,K♣,Q♦,A♣,3♦,6♦,5♥,10♣,Q♣,2♠
2♥,2♣,K♥,A♥,8♦,6♠,8♣,10♠,10♥,5♣,3♥,Q♥,K♦
5♠,5♦,J♣,J♥,J♦,9♠,2♦,8♥,9♣,4♥,10♦,6♣,3♠
3♣,A♦,K♠,4♦,7♣,4♣,A♠,4♠,7♥,J♠,9♥,7♦,9♦
glob
hace que sea conveniente leer todos los subdirectorios de una profundidad fija dada, como en glob "*/*/*"
. Lo he encontrado útil en varias ocasiones.