【问题标题】:Getting the list of files sorted by modification date in Perl在 Perl 中获取按修改日期排序的文件列表
【发布时间】:2014-01-09 00:12:20
【问题描述】:

我正在尝试获取按修改日期排序的文件列表。我从 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";
}

我在我的 Windows XP 32 位机器上使用 Strawberry Perl 版本 5.12.1.0 运行它。

Windows 上的目录列表是:

输出是:

输出对我来说没有多大意义。这段代码出了什么问题,foreach 循环究竟是如何对文件列表进行排序的?

【问题讨论】:

    标签: perl sorting date


    【解决方案1】:

    该代码至少存在 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(1970 年 1 月 1 日 0:00:00 UTC)转换为您的时区。

    第三,它期望$path 以目录分隔符结尾,而您传递的是"."。您需要传递"./",或者更好的是,修复它以便函数在需要时附加分隔符。

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

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

    【讨论】:

    • 非常感谢 cjm!对我来说不好的是没有抓住那个!从你的回答中学到了很多。再次感谢。
    【解决方案2】:

    使用Perlsort 函数。它速度更快,并且您无需哈希即可获得所需的内容。

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

    @s = 排序 {-s $a -s $b || -M $b -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;
    }
    

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

      • 谢谢大家!我的坏不能早点发现!
      【解决方案4】:

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

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

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

      请注意,以上是在相当高端的 Linux 刀片系统上,因此每个计算机/操作系统的 YMMV...

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-05-14
        • 1970-01-01
        • 1970-01-01
        • 2011-12-25
        • 1970-01-01
        • 2016-04-01
        相关资源
        最近更新 更多