2011-01-10 40 views
4

変更日順にソートされたファイルのリストを取得しようとしています。サンプルプログラムをSort Directory and list files based on date and timeに変更して実行しようとしました。Perlの変更日でソートされたファイルのリストを取得する

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上のディレクトリリストは次のとおりです。

alt text

出力は次のようになります。

alt text

出力は私にはあまり意味がありません。このコードで何がうまくいかず、foreachループがファイルのリストをどのようにソートするのですか?

答えて

4

get_sorted_filesの場合、$dirはディレクトリ名ではなくグロブです。おそらく、あなたは$pathを意味しましたか?

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

はあなたに暴徒をありがとう...コンピュータ/ OSごとYMMVので、かなりハイエンドのLinuxブレードシステム上にあることを

注意!私の悪いことは早くそれをキャッチできませんでした! – rkg

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"; 
} 

まず、あなたは$pathに元のコードで$dirの名前を変更しますが、mapラインでそれを変更しませんでした。 $dirはディレクトリハンドルです。それはGLOB(0x ...)がどこから来ているかです。

第2に、悪いパス名をstatに渡していたため、すべての変更日が「Wed Dec 31 16:00:00 1969」となっています。 (stat($_))[9]は空のリストを返していました(正しいパス名の代わりにGLOB(0x3f9b38)status.txtのようなファイルを探していたため)、ハッシュは実際にファイル名をキーと値の両方として含んでいます。最初のファイル名はキーで、2番目のファイル名は3番目のファイル名、3番目のファイル名は次のようなものでした。 localtimeは、ファイル名を数値に変換していました(0を生成)。その後、エポック時間0(1970年1月1日0:00:00 UTC)をタイムゾーンに変換していました。

第3に、$pathはディレクトリセパレータで終了し、"."を渡しています。 "./"を渡す必要があります。必要に応じて区切り文字が追加されるように修正することをお勧めします。

第4に、grepはもはや何もしなかったので削除する必要があります。 (元のコードでは、特定のファイル名のみを選択したが、パターンを変更して一致するようにした。

ファイル名のソート方法:get_sorted_filesは、パス名と変更時刻のリストを返す。 %filesハッシュ。 keys %filesは、キーのリスト(ファイル名)を返し、関連する値(変更時刻)の数値比較によってソートします。

+0

おかげでcjm!それを捕らえないように私の部分に悪い!あなたの答えからかなり学んだ。再度、感謝します。 – rkg

6

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; 
} 
0

を、あなたはPerlは、ソートを行うにはネイティブツールを使用するよりも大幅に遅くなることがあります。

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

しかし、(opendirsort -Mを使用)上記溶液中のコード30-45秒長くかかるから:たとえば、私のマシン上で、莫大(341kファイル)ディレクトリに、これは約1.5分かかります。はるかに高速であるだけでなく、Perlがメモリ内に配列全体を格納するのを避けることもできます。これは単独で勝利することができます。上記

関連する問題