22

Perl 中是否有一种优雅的方式来查找目录中的最新文件(按修改日期最新)?

到目前为止,我正在搜索我需要的文件,并为每个文件获取它的修改时间,推入一个包含文件名、修改时间的数组,然后对其进行排序。

肯定有更好的办法。

4

6 回答 6

26

如果您需要排序列表(而不仅仅是第一个,请参阅 Brian 的答案),您的方式是“正确”的方式。如果您不喜欢自己编写该代码,请使用

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

注意:对defined()结果的测试readdir()是因为如果你只测试一个名为'0'的文件会导致循环失败if (my $file = readdir($DH))

于 2008-11-30T14:41:00.290 回答
15

您不需要将所有修改时间和文件名保存在一个列表中,而且您可能不应该这样做。您需要做的就是查看一个文件,看看它是否比您之前看到的最旧的文件更旧:

{
    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";
}
于 2008-11-30T17:25:59.850 回答
11

您可以尝试使用 shell 的ls命令:

@list = `ls -t`;
$newest = $list[0];
于 2008-11-30T09:51:37.287 回答
6

假设您知道$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)文件系统中的特殊文件。

于 2008-11-30T09:52:25.443 回答
2

如果您不能ls像@Nathan 建议的那样让您进行排序,那么您可以通过仅保留迄今为止看到的最新修改时间和相关文件名并在每次在目录中找到更新文件时替换它来优化您的过程。无需保留任何您知道比您目前看到的最新文件更旧的文件,当然也不需要对它们进行排序,因为您可以在从目录中读取时检测哪个是最新的。

于 2008-11-30T13:52:01.137 回答
-1

主题是旧的,但也许有人会尝试它 - 它不是可移植的(仅限类 Unix 系统),但它非常简单并且有效:

chdir $directory or die "不能改变目录";

我的 $newest_file = bash -c 'ls -t | head -1';

咀嚼 $newest_file;

打印 "$newest_file \n";

于 2012-04-10T23:18:19.697 回答