[转]遍历文件夹的方法比较

 

遍历文件夹的方法比较

本贴对三种遍历文件夹方法比较。


1. 使用File::Find;
2. 递归遍历。(遍历函数为lsr)
3. 使用队列或栈遍历。(遍历函数为lsr_s)


1.use File::Find

  1. #!/usr/bin/perl -W
  2. #
  3. # File: find.pl
  4. # Author:  路小佳
  5. # License: GPL-2
  6. use strict;
  7. use warnings;
  8. use File::Find;
  9. my ($size, $dircnt, $filecnt) = (0, 0, 0);
  10. sub process {
  11.     my $file = $File::Find::name;
  12.     #print $file, "/n";
  13.     if (-d $file) {
  14.         $dircnt++;
  15.     }
  16.     else {
  17.         $filecnt++;
  18.         $size += -s $file;
  19.     }
  20. }
  21. find(/&process, '.');
  22. print "$filecnt files, $dircnt directory. $size bytes./n";

复制代码

 

2. lsr递归遍历

  1. #!/usr/bin/perl -W
  2. #
  3. # File: lsr.pl
  4. # Author: 路小佳
  5. # License: GPL-2
  6. use strict;
  7. use warnings;
  8. sub lsr($) {
  9.     sub lsr;
  10.     my $cwd = shift;
  11.     local *DH;
  12.     if (!opendir(DH, $cwd)) {
  13.         warn "Cannot opendir $cwd: $! $^E";
  14.         return undef;
  15.     }
  16.     foreach (readdir(DH)) {
  17.         if ($_ eq '.' || $_ eq '..') {
  18.             next;
  19.         }
  20.         my $file = $cwd.'/'.$_;
  21.         if (!-l $file && -d _) {
  22.             $file .= '/';
  23.             lsr($file);
  24.         }
  25.         process($file, $cwd);
  26.     }
  27.     closedir(DH);
  28. }
  29. my ($size, $dircnt, $filecnt) = (0, 0, 0);
  30. sub process($$) {
  31.     my $file = shift;
  32.     #print $file, "/n";
  33.     if (substr($file, length($file)-1, 1) eq '/') {
  34.         $dircnt++;
  35.     }
  36.     else {
  37.         $filecnt++;
  38.         $size += -s $file;
  39.     }
  40. }
  41. lsr('.');
  42. print "$filecnt files, $dircnt directory. $size bytes./n";

复制代码

 

3. lsr_s栈遍历

  1. #!/usr/bin/perl -W
  2. #
  3. # File: lsr_s.pl
  4. # Author: 路小佳
  5. # License: GPL-2
  6. use strict;
  7. use warnings;
  8. sub lsr_s($) {
  9.     my $cwd = shift;
  10.     my @dirs = ($cwd.'/');
  11.     my ($dir, $file);
  12.     while ($dir = pop(@dirs)) {
  13.         local *DH;
  14.         if (!opendir(DH, $dir)) {
  15.             warn "Cannot opendir $dir: $! $^E";
  16.             next;
  17.         }
  18.         foreach (readdir(DH)) {
  19.             if ($_ eq '.' || $_ eq '..') {
  20.                 next;
  21.             }
  22.             $file = $dir.$_;        
  23.             if (!-l $file && -d _) {
  24.                 $file .= '/';
  25.                 push(@dirs, $file);
  26.             }
  27.             process($file, $dir);
  28.         }
  29.         closedir(DH);
  30.     }
  31. }
  32. my ($size, $dircnt, $filecnt) = (0, 0, 0);
  33. sub process($$) {
  34.     my $file = shift;
  35.     print $file, "/n";
  36.     if (substr($file, length($file)-1, 1) eq '/') {
  37.         $dircnt++;
  38.     }
  39.     else {
  40.         $filecnt++;
  41.         $size += -s $file;
  42.     }
  43. }
  44. lsr_s('.');
  45. print "$filecnt files, $dircnt directory. $size bytes./n";

复制代码

 

对我的硬盘/dev/hda6的测试结果。


1: File::Find

  1. 26881 files, 1603 directory. 9052479946 bytes.
  2. real    0m9.140s
  3. user    0m3.124s
  4. sys     0m5.811s

复制代码

2: lsr

  1. 26881 files, 1603 directory. 9052479946 bytes.
  2. real    0m8.266s
  3. user    0m2.686s
  4. sys     0m5.405s

复制代码

3: lsr_s

  1. 26881 files, 1603 directory. 9052479946 bytes.
  2. real    0m6.532s
  3. user    0m2.124s
  4. sys     0m3.952s

复制代码

测试时考虑到cache所以要多测几次取平均, 也不要同时打印文件名, 因为控制台是慢设备, 会形成瓶颈。
lsr_s之所以用栈而不是队列来遍历,是因为Perl的push shift pop操作是基于数组的, push pop这样成对操作可能有优化。内存和cpu占用大小顺序也是1>2>3.

  1.                            CPU load          memory
  2. use File::Find             97%               4540K
  3. lsr                        95%               3760K
  4. lsr_s                      95%               3590K

复制代码

 

结论: 强烈推荐使用lsr_s来遍历文件夹。


=============再罗嗦几句======================
从执行效率上来看,find.pl比lsr.pl的差距主要在user上, 原因是File::Find模块选项较多,条件判断费时较多,而lsr_s.pl比lsr.pl在作系统调用用时较少, 是因为递归时程序还在保存原有的文件句柄和函数恢复现场的信息,所以sys费时较多。 所以lsr_s在sys与user上同时胜出是不无道理的。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值