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

w7t8yxp5  于 2023-03-03  发布在  Perl
关注(0)|答案(5)|浏览(194)

我正在尝试获取按修改日期排序的文件列表。我修改了 * 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循环对文件列表的排序到底是如何的?

sqyvllje

sqyvllje1#

该代码至少有两个问题。下面是一个更好的版本:

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行中更改它。这就是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返回键(文件名)的列表,并根据关联值(修改时间)的数值比较对它们进行排序。

x7yiwoj4

x7yiwoj42#

使用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;
}
wgx48brx

wgx48brx3#

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

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

pes8fvy94#

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

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

但是上述解决方案中的代码(使用opendirsort -M)要多花30-45秒,不仅速度快得多,而且还可以避免Perl将整个数组存储在内存中,这本身就是一种优势。
请注意,以上是在一个相当高端的Linux刀片系统上,因此每台计算机/OS的YMMV...

juud5qan

juud5qan5#

使用一行程序:

perl -E '
    say join "\n",
    sort { -M $a <=> -M $b }
    grep -f, @ARGV
' -- *

相关问题