2009-01-12 14 views
8

Cuando leo un directorio en Perl con opendir, readdir y closedir, la función readdir no parece leer los archivos en un orden específico (que puedo decir).¿Cómo puedo leer los archivos en un directorio en orden ordenado?

estoy leyendo un directorio que tiene subdirectorios llamados por fecha y hora época:

1224161460 
1228324260 
1229698140 

quiero leer en estos directorios en orden numérico, lo que pondría en primer lugar los directorios más antiguas.

Cuando uso readdir, el primero que dice es 1228324260, que es el del medio. Sé que podría poner los contenidos del directorio en una matriz y ordenar la matriz, pero ¿hay alguna opción que pueda pasar al readdir para leer en orden ordenado? ¿O tal vez una forma más elegante de lograr esto que empujar todo en conjunto y ordenar la matriz? Probablemente existan módulos para hacer esto también, pero es difícil instalar módulos en nuestro entorno, así que, a menos que sea un módulo integrado, preferiría no usar módulos ...

¡Gracias!

EDITAR a lo solicitado, estoy publicando el código que estoy usando:

opendir(my $data_dh, $data_dir) or die "Cannot open $data_dir\n"; 
while (my $name = readdir($data_dh)) { 
    next if ($name eq '.' or $name eq '..'); 
    my $full_path = "${data_dir}/${name}"; 
    next unless (-d $full_path); 
    process_dir($full_path); 
} 
closedir($data_dh); 
+0

estoy usando Perl 5.8.2 en una caja de AIX, si se hace una diferencia – BrianH

+0

Sé que es un script sencillo, pero puede publicar su código por lo que no tenemos que reproducirlo? –

+1

El signo & antes de process_dir no es necesario y, en algunas circunstancias, puede ser dañino. Te aconsejaría que lo quites. –

Respuesta

13

readdir puede ser llamado en su contexto matriz, por lo que acaba de hacer esto:

opendir(my $data_dh, $data_dir) or die "Cannot open $data_dir\n"; 
my @files = sort { $a <=> $b } readdir($data_dh); 
while (my $name = shift @files) { 
... 
+0

No necesita el bloque {$ a <=> $ b}; el valor predeterminado aquí. – Svante

+2

NO, el valor predeterminado NO es suficiente. El valor predeterminado es ordenado léxicamente, no numéricamente. Las marcas de tiempo anteriores a 2001-09-09T01: 46: 40 ordenarían como más tarde que la mayoría de las marcas de tiempo posteriores, porque rompieron la barrera de 1,000,000,000 de segundos. –

+0

Realmente, opendir es exagerado aquí. Su mejor opción sería usar glob() ... no hay controladores de directorio de los que preocuparse. –

5

Puedes probarlo con un poco de magia Glob, glob parece funcionar de una manera ordenada, así que esto:

# Glob in scalar context iterates the result set internally 
while(defined(my $dir = glob($dir . '/*'))){ 
    print $dir, "\n"; 
    # $dir is fed ordered and with full names. 
} 

o

# Glob in list context returns all results. 
for(glob($dir.'/*')){ 
    print $dir , "\n"; 
    # also ordered. 
} 

debería funcionar. Sólo tenga cuidado con pegote, porque esto:

for(0..20){ 
    printf "%30s|%30s\n", glob($dir.'/*'), glob($dir.'/*'); 
} 

hace algo semi-mágico, e imprime el contenido dir dos veces en cada línea. es decir:

/foo/bar/a | /foo/bar/a 
/foo/bar/b | /foo/bar/b 
/foo/bar/c | /foo/bar/c 
/foo/bar/d | /foo/bar/d 
+1

Esta es probablemente la mejor manera de hacerlo. Opendir es realmente exagerado aquí. –

5

sólo un tiro de un sort frente a cualquier operador de la lista que desea volver a ordenar. No es necesario almacenar los resultados en una matriz tampoco. Puede utilizar un foreach:

opendir my($dh), $dirname or die "Could not open directory [$dirname]: $!"; 

foreach my $file (sort { $a <=> $b } readdir $dh) 
    { 
    ... 
    } 
+0

++ para simplificar, pero creo que alguien rompió su marcado de código (el bloque de clasificación). – converter42

+0

Ah, sí, a los bloques pre no les gustan los soportes angulares, a pesar de que salen muy bien en la vista previa. –

Cuestiones relacionadas