perl - studio - ¿Cómo puedo encontrar el archivo creado más nuevo en un directorio?
visual studio installer (6)
¿Hay alguna manera elegante en Perl para encontrar el archivo más nuevo en un directorio (el más nuevo por fecha de modificación)?
Lo que tengo hasta ahora es buscar los archivos que necesito, y para cada uno, obtener su tiempo de modificación, presionar en una matriz que contenga el nombre del archivo, modificar la hora y luego ordenarla.
Debe haber una mejor manera.
Si no puedes dejar que haga la clasificación por ti como lo sugiere @Nathan, entonces puedes optimizar tu proceso manteniendo solo el tiempo de modificación más nuevo y el nombre de archivo asociado hasta el momento y reemplazándolo cada vez que encuentres un archivo más nuevo en el directorio. No es necesario guardar ningún archivo que sepa que es más antiguo que el más reciente que haya visto hasta el momento y, desde luego, no es necesario ordenarlos, ya que puede detectar cuál es el más nuevo mientras lee desde el directorio.
Suponiendo que conoce el $DIR
que desea buscar:
opendir(my $DH, $DIR) or die "Error opening $DIR: $!";
my %files = map { $_ => (stat("$DIR/$_"))[9] } grep(! /^/./.?$/, readdir($DH));
closedir($DH);
my @sorted_files = sort { $files{$b} <=> $files{$a} } (keys %files);
# $sorted_files[0] is the most-recently modified. If it isn''t the actual
# file-of-interest, you can iterate through @sorted_files until you find
# the interesting file(s).
El grep
que envuelve el readdir
filtra el "." y ".." archivos especiales en un sistema de archivos UNIX (-ish).
Tu camino es el "correcto" si necesitas una lista ordenada (y no solo la primera, mira la respuesta de Brian para eso). Si no te gusta escribir ese código tú mismo, usa esto
use File::DirList;
my @list = File::DirList::list(''.'', ''M'');
Personalmente, no iría con el método ls -t
que implica bifurcar otro programa y no es portátil. ¡Difícilmente lo que llamaría "elegante"!
Con respecto a la solución codificada a mano de la solución de rjray, la cambiaría ligeramente:
opendir(my $DH, $DIR) or die "Error opening $DIR: $!";
my @files = map { [ stat "$DIR/$_", $_ ] } grep(! /^/./.?$/, readdir($DH));
closedir($DH);
sub rev_by_date { $b->[9] <=> $a->[9] }
my @sorted_files = sort rev_by_date @files;
Después de esto, @sorted_files
contiene la lista ordenada, donde el 0 ° elemento es el más nuevo y cada elemento contiene una referencia a los resultados de stat
, con el nombre del archivo en el último elemento:
my @newest = @{$sorted_files[0]};
my $name = pop(@newest);
La ventaja de esto es que es más fácil cambiar el método de clasificación más tarde, si lo desea.
EDITAR: aquí hay una versión más fácil de leer (pero más larga) del escaneo de directorio, que también asegura que solo se agreguen los archivos simples a la lista:
my @files;
opendir(my $DH, $DIR) or die "Error opening $DIR: $!";
while (defined (my $file = readdir($DH))) {
my $path = $DIR . ''/'' . $file;
next unless (-f $path); # ignore non-files - automatically does . and ..
push(@files, [ stat(_), $path ]); # re-uses the stat results from ''-f''
}
closedir($DH);
NB: la prueba para defined()
en el resultado de readdir()
se debe a que un archivo llamado ''0'' provocaría que el ciclo falle si solo prueba if (my $file = readdir($DH))
podrías intentar usar el comando ls
del intérprete de comandos:
@list = `ls -t`;
$newest = $list[0];
El sujeto es viejo, pero tal vez alguien lo intente; no es portátil (solo sistemas tipo Unix), pero es bastante simple y funciona:
chdir $ directorio o muere "no se puede cambiar el directorio";
mi $ newest_file =
bash -c ''ls -t | head -1''
bash -c ''ls -t | head -1''
;chomp $ newest_file;
imprimir "$ newest_file / n";
No necesita mantener todos los tiempos de modificación y nombres de archivos en una lista, y probablemente no debería. Todo lo que necesita hacer es mirar un archivo y ver si es más antiguo que el más antiguo que haya visto anteriormente:
{
opendir my $dh, $dir or die "Could not open $dir: $!";
my( $newest_name, $newest_time ) = ( undef, 2**31 -1 );
while( defined( my $file = readdir( $dh ) ) ) {
my $path = File::Spec->catfile( $dir, $file );
next if -d $path; # skip directories, or anything else you like
( $newest_name, $newest_time ) = ( $file, -M _ )
if( -M $path < $newest_time );
}
print "Newest file is $newest_name/n";
}