2014-08-27 40 views
2

=================Perl:查找大于X分钟数的文件的最快方法,将最早排序到最新?

1.查找文件不是几分钟的X数的

2.处理他们从最旧到最新

下面的代码工作正常,但是该目录包含3百万个文件。因此我需要优化它以更快地找到文件。我不必担心文件的内容只是名称。

########################### 
sub get_files_to_process{ 
########################### 
# Declare arrays 
my @xmlfiles; 
my @qulfiedfiles; 

# Declare a Dictionary 
my %filedisc; 

opendir(my $dh, $maindir) or die "opendir($maindir): $!"; 

# Read all the files 
while (my $de = readdir($dh)) { 
    # get the Full path of the file 
    my $f = $maindir . $de; 
    # If File is there and has .xml Extension 
    if (-f $f && $f=~ /\.xml/){ 
     # Put it in a XMLFILES Array 
     push (@xmlfiles, $f); } 
    } 
    closedir($dh); 


# For every file in directory 
for my $file (@xmlfiles) { 

    # Get stats about a file 
    my @stats = stat($file); 

    # If time stamp is older than minutes provided 
    if ($stats[9] <= ($now - (($minutesold * 60)))){ 

     # Put the File and Time stamp in the dictionary 
     $filedisc{$file} = $stats[9]; 
    } 
} 

# For every file in the dictionary sort based on the timestamp oldest files first 
for my $x (sort {$filedisc{$a} <=> $filedisc{$b} or $a cmp $b } keys %filedisc) { 

    # Put the qualified files (Based on the age) in a list 
     push(@qulfiedfiles, $x);} 

更新:到目前为止,这似乎是做有前途的,更多的测试:

########################## 
sub get_files_count{ 
########################## 

    my $cmd= "find $maindir -maxdepth 1 -name '*.xml' -mmin +$minutesold -printf \"%T+\t%p\\n\"| sort"; 
    my @output = `$cmd`; 

    if (@output){ 
     foreach my $line (@output){ 
      chomp $line; 
      push (@files2process, (split '\t', $line)[ -1 ]); 
     } 
     } 
    } 
+2

我还没有测试您的代码与3_000_000条目的目录。在我们开始讨论优化代码的方法之前,为什么不使用'Devel :: NYTProf'来确定代码花费最多的时间? – DavidO 2014-08-27 21:21:04

+0

一旦你有你的名单,你如何处理文件? – ThisSuitIsBlackNot 2014-08-27 21:35:42

+0

@ThisSuitIsBlackNot,一旦我有文件列表,我根据文件的名称将文件移动到适当的子目录(并创建子目录(如果尚未存在的话)),则此脚本将每隔cron用完5到10分钟,Enterpise应用程序会生成大量的xml文件,这将会培养这些文件 – Grene 2014-08-28 01:30:01

回答

2

使用文件::查找

use File::Find 

$\ = "\n"; 

my @files; 

# find all files newer that 9 minutes 
File::Find::find({wanted => \&wanted}, '.'); 

# sort them and print them 
print for map { $_-[0] } sort { $b->[1] <=> $a->[1] } @files; 

exit; 

sub wanted { 
    ((-M) < (9/(24 * 60))) && -f && push @files, [ $_, (-M) ]; 
} 

这是递归的 - 所以它会去通过所有的子目录(但我从你的问题中假设没有)。

此外,上面大多是find2perl自动生成的代码,它将大部分unix查找参数转换为perl脚本 - 很酷且很快。

我还没有用9分钟测试-M位 - 我在最后9分钟内没有保存任何东西。

+1

您是否将此建议的运行时间与OP当前使用的运行时间进行了比较,还是仅凭直觉就会明显更快? ......因为我们不想因为微不足道的改进或回归而过于兴奋。 – DavidO 2014-08-28 00:43:26

1

我会分两步解决这个问题:

1)创建一个Linux::Inotify2过程,在什么目录上的每一个变化会更新一些cahce文件(如可保存或此类)

例如您将拥有所有文件统计信息的实际缓存。加载一个文件可保存在每次运行

2)需要搜索时,只加载可存储,搜索一个大哈希作为收集统计信息3M文件的速度...

+0

感谢您的输入。这是一个非常聪明的解决方案,我一定会研究它。不幸的是,这是企业应用程序有很多其他的警告。 – Grene 2014-09-15 13:44:45

+0

@Grene刚刚对同样的评论再次评论过你。所以,可能仍然在与这个问题作斗争。你能否更具体一些?例如。使用的操作系统等?而且你在评论中说过_这会修饰这些文件_所以,当你将它们移动到子目录时,它们如何在短时间内再次成为3_000_000,所以你需要这样极端的统计速度?这听起来像是废话......请问一个真正的问题 - 不是一个低俗的问题 - 否则,你不能得到任何相关的答案...... – jm666 2014-09-15 13:55:04

+0

对不起,我只是在我的评论中纠正了一个错字。正如我发布了关于这个问题的更新,它在一个可接受的时间范围内工作,并且比我之前的工作速度快得多。更多信息,问题是真实的,脚本每运行30分钟,应用程序会在该时间框架内生成大约100k xml的文件,但是最初的文件积压非常大,并且通过NFS挂载。处理这些文件以便生成它们需要很长时间。脚本是更大的应用程序的一部分,所以对不起,我没有提供足够的细节。 – Grene 2014-09-16 21:50:27

0

我知道这是一个古老的题。我主要是回答“未来世代”。

大部分时间很可能会花费在排序 3百万个文件项,因为排序操作是非线性的(即排序越慢越慢的文件越多),也因为大多数stat调用发生在比较中,这主要是由于排序而发生的。如果你可以避免排序,你也将自动避免大部分的统计调用,并节省大量的时间。如果你可以避免排序,你也可以自动避免大部分统计调用,并节省大量的时间。由于您的任务只是“将文件移动到合适的目录中”,因此我只需简单地为每个找到的符合条件的文件调用处理方法,就是您找到的时刻,而不是先创建一个巨大的列表,然后使用一堆的循环进行排序,然后浏览庞大的列表并以不需要首先排序的方式进行处理。

一个来自你自己的脚本的例子:“find”,不像说“ls”,不是在内存中创建一个文件列表 - 它在每个文件发现它时执行它的命令。这就是为什么它不会与巨大的目录爆炸,不像“ls”。只是做它就像发现它^^

相关问题