获取按Perl中的修改日期排序的文件列表

时间:2011-01-10 20:19:26

标签: perl sorting date

我正在尝试按修改日期排序文件列表。我从 Sort Directory and list files based on date and time 修改了示例程序并尝试运行它。

sub get_sorted_files {
    my $path = shift;
    opendir my($dir), $path or die "can't opendir $path: $!";
    my %hash = map {$_ => (stat($_))[9]}
               map  { "$dir$_" }
               grep { m/.*/i }
               readdir $dir;
    closedir $dir;
    return %hash;
}

my %files = get_sorted_files(".");
foreach my $keys (sort{$files{$a} <=> $files{$b}} keys %files) {
    print "$keys\t", scalar localtime($files{$keys}), "\n";
}

我在使用Strawberry Perl版本5.12.1.0的Windows XP 32位计算机上运行此程序。

Windows上的目录列表是:

alt text

输出结果为:

alt text

输出对我来说没什么意义。这段代码出了什么问题以及foreach循环对文件列表进行排序的确切原因是什么?

4 个答案:

答案 0 :(得分:7)

该代码至少存在2个问题。这是一个更好的版本:

use strict;
use warnings; # I bet you weren't using this, because it produced a lot

sub get_sorted_files {
   my $path = shift;
   opendir my($dir), $path or die "can't opendir $path: $!";
   my %hash = map {$_ => (stat($_))[9] || undef} # avoid empty list
           map  { "$path$_" }
           readdir $dir;
   closedir $dir;
   return %hash;
}

my %files = get_sorted_files("./");
foreach my $key (sort{$files{$a} <=> $files{$b}} keys %files) {
   print "$key\t", scalar localtime($files{$key}), "\n";
}

首先,您将原始代码中的$dir重命名为$path,但未在map行中更改它。您的$dir是目录句柄;这就是GLOB(0x ...)的来源。

其次,所有修改日期均为“Wed Dec 31 16:00:00 1969”,因为您将错误的路径名传递给stat(stat($_))[9]返回一个空列表(因为您正在查找类似GLOB(0x3f9b38)status.txt的文件而不是正确的路径名),因此哈希实际上包含文件名作为键和值。第一个文件名是一个键,第二个是它的值,第三个是下一个键,依此类推。 localtime正在将文件名转换为数字(产生0),然后将纪元时间0(1-Jan-1970 0:00:00 UTC)转换为您的时区。

第三,它希望$path以目录分隔符结束,并且您传递"."。您需要传递"./",或者更好,然后修复它,以便函数在需要时添加分隔符。

第四,grep不再做任何事情,应该删除。 (在原始代码中,它只选择了某些文件名,但您更改了模式以匹配任何内容。)

关于如何对文件名进行排序:get_sorted_files返回路径名和修改时间列表,您将其存储到%files哈希中。 keys %files返回键列表(文件名),并通过相关值(修改时间)的数字比较对它们进行排序。

答案 1 :(得分:6)

使用Perlsort功能。它更快,你会得到你想要的没有哈希。

  

文件大小,然后是文件年龄:

     

@s = sort {-s $ a&lt; =&gt; -s $ b || -M $ b&lt; =&gt; -M $ a} @a;

了解上述内容后,我们可以说出如下内容:

sub get_sorted_files {
   my $path = shift;
   opendir my($dirh), $path or die "can't opendir $path: $!";
   my @flist = sort {  -M $a <=> -M $b } # Sort by modification time
               map  { "$path/$_" } # We need full paths for sorting
               readdir $dirh;
   closedir $dirh;
   return @flist;
}

答案 2 :(得分:4)

get_sorted_files中,$dir是一个glob,而不是目录名。也许你的意思是$path

my %hash = map {$_ => (stat($_))[9]}
           map  { "$path/$_" }              # $path, not $dir
           grep { m/.*/i }
           readdir $dir;

答案 3 :(得分:0)

对于非常大的目录,您可能会发现Perl明显慢于使用本机工具进行排序。例如,在我的机器上,在一个巨大的(341k文件)目录上,这需要大约1.5分钟:

my $mostrecent = `/bin/ls --full-time -lta $dir | head -1 2>/dev/null`;

但上述解决方案中的代码(使用opendirsort -M)需要30-45秒的时间。它不仅速度明显更快,还可以避免Perl将整个数组存储在内存中,这本身就是一种胜利。

请注意,上面是一个相当高端的Linux刀片系统,所以YMMV是每台计算机/操作系统......