ファイルのリストを更新順でソート

CGIテクニック集トップへ





概要

ファイルリスト表示をファイル更新時間順で行います。単純なリスト表示はディレクトリ内のファイルの一覧表示を参照ください。アルファベット順でのソートはファイルのリストをアルファベット順でソートを参照ください。 アップノーティス等で使用されています。

必用な処理

  1. オープンするディレクトリを開く
  2. ディレクトリ内のファイルを配列に挿入
  3. 配列内から必用なファイルのみ抽出
  4. ファイル名と更新時間が対応したハッシュを作る
  5. ハッシュのキーを更新順にソート
  6. ハッシュの内容を表示

サンプルコード

 my $dir = "filedir";
 
 opendir(DIR, "$dir") or die "ディレクトリ$dirが開けません";
 my @filelist = grep !/^\./, readdir DIR;
 closedir(DIR);
 
 my %timefile;
 foreach my $file (@filelist){
    my $mtime = (stat("$dir/$file"))[9];
    push @{$timefile{$mtime}},"$file";
 }
 
 print "<ul>\n";
 foreach my $time (sort {$b <=> $a} keys %timefile){
     foreach (@{$timefile{$time}}){
         print "<li>$_</li>\n";
     }
 }
 print "</ul>\n";

コードの解説

 my $dir = "filedir";
 
 opendir(DIR, "$dir") or die "ディレクトリ$dirが開けません";
 my @filelist = grep !/^\./, readdir DIR;
 closedir(DIR);

$dirにはリスト表示させたいディレクトリ名を保存します。 opendirで$dirをオープンします。失敗すればエラーメッセージと共にスクリプトは終了します。 ファイルハンドルDIRの内容をreaddirで取り込みます。その出力をgrep !/^\./により.で始まるファイル名を除いて配列@filelistに入力します。抽出したいファイル名だけ@filelistに入れるなどの処理もgrepにより可能です。@filelistにはディレクトリfiledir内に格納されている全てのファイル(.から始まるファイルを除く)が入っています。ファイルハンドルDIRに対して必用な処理はこれだけなのでDIRをクローズします。

 my %timefile;
 foreach my $file (@filelist){
    my $mtime = (stat("$dir/$file"))[9];
    push @{$timefile{$mtime}},"$file";
 }

$fileは時間を取得したいファイル。stat関数によりそのファイルの属性を配列にて取得することができます。statが返す配列の10番目の要素(0から始まる要素番号9)が更新時間情報なのでそれを$mtimeに格納する。他の返り値は捨てています。時間はepochなので1970年1月1日0時0分0秒からの秒数になります。

他のstatの返り値は、

 my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,
     $mtime,$ctime,$blksize,$blocks)=stat("$file");

のようになります。この場合アクセス時間は$atime, inode変更時間は$ctimeに格納されます。$sizeによりファイルサイズも取得できます。

そして更新時間とファイル名が対応したハッシュを作成します。これで後に更新時間を指定することでファイル名を抽出することができます。

ここで

 push @{$timefile{$mtime}},"$file";

としているのは、まったく同時刻に変更したファイルが複数あった場合に

 $timefile{$mtime} = "$file";

のように単純に挿入した場合他の同じ時刻に更新されたファイル名に上書きされてしまい全てを記憶することができなくなるからです。時刻情報を持つハッシュに配列のリファレンスとすることでその時刻に対応するファイルを複数記憶します。

 print "<ul>\n";
 foreach my $time (sort {$b <=> $a} keys %timefile){
     foreach (@{$timefile{$time}}){
         print "<li>$_</li>\n";
     }
 }
 print "</ul>\n";

foreachブロックでファイルを一つずつ表示します。この時にファイル更新時間でソートします。{$b <=> $a}とするのはepoch時間が大きい順、つまり最新順にソートするためです。keys %timefileでハッシュ%timefileのキーである更新時間のみ抽出しそれでforeachを回します。$timefile{$_}は配列のリファレンスで複数ファイル名が記憶されている可能性があるのでその配列を展開しそれぞれ一つずつ表示させることで同時刻に更新された複数ファイルの表示を実現しています。

関連するCGIテクニック

ディレクトリ(フォルダ)内のファイルの一覧表示
ファイルのリストをアルファベット順でソート
サブディレクトリ内にある全てのファイルを抽出する方法