遍历文件夹的方法比较

本贴对三种遍历文件夹方法比较。
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上同时胜出是不无道理的。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值