Как я могу найти самый новый созданный файл в каталоге?

Есть ли в Perl элегантный способ найти самый новый файл в каталоге (самый новый по дате изменения)?

Пока у меня есть поиск файлов, которые мне нужны, и для каждого из них получают свое время модификации, помещают в массив, содержащий имя файла, время модификации, а затем сортируют его.

Должен быть лучший способ.

6 ответов

Решение

Ваш путь - "правильный", если вам нужен отсортированный список (и не только первый, см. Ответ Брайана за это). Если вы не хотите писать этот код самостоятельно, используйте это

use File::DirList;
my @list = File::DirList::list('.', 'M');

Лично я бы не пошел с ls -t метод - это включает в себя разветвление другой программы, и она не переносима. Вряд ли то, что я бы назвал "элегантным"!


Что касается решения от RJRAY, я бы немного его изменил:

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;

После этого, @sorted_files содержит отсортированный список, где 0-й элемент является самым новым файлом, а каждый элемент сам содержит ссылку на результаты statс самим именем файла в последнем элементе:

my @newest = @{$sorted_files[0]};
my $name = pop(@newest);

Преимущество этого в том, что при желании легче изменить метод сортировки.


РЕДАКТИРОВАТЬ: вот более простая для чтения (но более длинная) версия сканирования каталогов, которая также гарантирует, что в список добавляются только простые файлы:

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: тест для defined() на результат readdir() потому что файл с именем '0' приведет к сбою цикла, если вы будете проверять только if (my $file = readdir($DH))

Вам не нужно хранить все времена изменения и имена файлов в списке, и вы, вероятно, не должны. Все, что вам нужно сделать, это посмотреть на один файл и посмотреть, старше ли он самого старого, который вы видели ранее:

{
    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";
}

Вы можете попробовать использовать оболочку ls команда:

@list = `ls -t`;
$newest = $list[0];

Предполагая, что вы знаете $DIR Вы хотите посмотреть в:

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).

grep это оборачивает readdir отфильтровывает "." и ".." специальные файлы в файловой системе UNIX(-ish).

Если ты не можешь позволить ls выполните сортировку за вас, как подсказывает @Nathan, затем вы можете оптимизировать свой процесс, сохранив только самое новое время модификации и связанное с ним имя файла, и заменять его каждый раз, когда вы найдете новый файл в каталоге. Не нужно хранить какие-либо файлы, которые, как вы знаете, старше, чем самый новый, который вы видели до сих пор, и, конечно, нет необходимости сортировать их, поскольку вы можете определить, какой из них самый новый, при чтении из каталога.

Тема старая, но, возможно, кто-то попробует ее - она ​​не переносима (только для Unix-подобных систем), но она довольно проста и работает:

каталог chdir $ или die "не может изменить каталог";

мой $ newest_file = bash -c 'ls -t | head -1';

chomp $ newest_file;

print "$ newest_file \ n";

Другие вопросы по тегам