我正在尝试按修改日期排序文件列表。我从 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上的目录列表是:
输出结果为:
输出对我来说没什么意义。这段代码出了什么问题以及foreach
循环对文件列表进行排序的确切原因是什么?
答案 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)
使用Perl的sort功能。它更快,你会得到你想要的没有哈希。
文件大小,然后是文件年龄:
@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`;
但上述解决方案中的代码(使用opendir
和sort -M
)需要30-45秒的时间。它不仅速度明显更快,还可以避免Perl将整个数组存储在内存中,这本身就是一种胜利。
请注意,上面是一个相当高端的Linux刀片系统,所以YMMV是每台计算机/操作系统......