2014-08-27 34 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」。只是做它就像發現它^^

相關問題