免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123下一页
最近访问板块 发新帖
查看: 18152 | 回复: 20
打印 上一主题 下一主题

遍历文件夹的方法比较。 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-03-10 18:41 |只看该作者 |倒序浏览
本贴对三种遍历文件夹方法比较。
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上同时胜出是不无道理的。

[ 本帖最后由 路小佳 于 2007-3-10 23:47 编辑 ]

论坛徽章:
0
2 [报告]
发表于 2007-03-10 18:58 |只看该作者
仙子好快,谢谢鼓励。
这两个遍历脚本我觉得已经努力按照C语言的风格优化了, 但是对我对Perl了解还不够, 如果代码还有明显的概念错误或性能还有提升的余地, 各位大虾不吝赐教。

论坛徽章:
0
3 [报告]
发表于 2007-03-10 22:46 |只看该作者
(-d $file && !-l $file)

类似这样的操作,第2个$file可以用_替换吧?表示重用前一个文件句柄.

论坛徽章:
0
4 [报告]
发表于 2007-03-10 22:49 |只看该作者
啊呀, 还有这样的用法, 谢谢指点。

论坛徽章:
0
5 [报告]
发表于 2007-03-10 23:16 |只看该作者
抱怨一下Perl语法, 像(-d $file && !-l _)这样的技巧性的东西太多导致了Perl的学习成本太高, 而Perl6更有发扬光大的趋势。这让我很不安。当初抱着《Perl高级编程》啃了三个月, 头大如斗, 还没看完就被催着还掉了。我看Perl当前应该做的优化性能和整合模块。Parrot这样的东西应该是Perl的希望, 而CPAN上模块虽多,质量却参差不齐(File::Find已经算很好用的模块了)。只是Perl6一直跳票, 还附带了许多新语法, 而整合模块这是本身又与Perl哲学不合(所谓哲学怕是一个借口, 大约是没人愿意也没人响应来做这事)。
最后用一句名言来反驳我自己:"当程序员还在用COBOL编程时,人类已经登上了月球。", 但是Perl虽好, 奈何学习成本太高。

论坛徽章:
0
6 [报告]
发表于 2007-03-10 23:45 |只看该作者
当程序员还在用COBOL编程时,人类已经登上了月球


那个时候有没有C程序?他们不会用汇编编的登月系统吧?

论坛徽章:
0
7 [报告]
发表于 2007-03-10 23:58 |只看该作者
这个名言好像是Stroustrup说的, 说服人们不要老做C++ vs Java的无意义的争吵。
老师也告诉我们, 任何语言只是工具, 就像建高楼的推土机,脚手架等等。就像从来没有人声称自己是“推土机高手”, 宣称自己是"XX语言"的高手也很可笑,最重要的是做设计高手。
但是Perl这个工具虽然用起来挺趁手, 但是按钮和注意事项太多,让我等初涉Perl的人有点目不暇接。比如像(!-l $file && -d _)这种, 刚才测试有了了1%~5%的提升, 高兴之余不免有点郁闷。

论坛徽章:
0
8 [报告]
发表于 2007-03-11 00:01 |只看该作者
原帖由 路小佳 于 2007-3-10 23:58 发表
这个名言好像是Stroustrup说的, 说服人们不要老做C++ vs Java的无意义的争吵。
老师也告诉我们, 任何语言只是工具, 就像建高楼的推土机,脚手架等等。就像从来没有人声称自己是“推土机高手”, 宣称自己是&q ...


Perl best practice里有讲这些的...
另外_是常用用法了,可能你用的少就不习惯吧.

论坛徽章:
0
9 [报告]
发表于 2007-03-11 00:05 |只看该作者
那个时候有没有C程序?他们不会用汇编编的登月系统吧?


地上的大多可能是C写的,登月的基本就是汇编写的了。前一段时间看了一段新闻,说美国宇航局专门派人到某电子废物处理中心买了一货柜旧电子产品,目的就是拆其中的8086来备用,因为现有的航天飞机和各种型号的火箭、导弹的核心都是她,这玩意还得继续维护直到退役。

从另一个角度想,中国的军工还是有后发优势的,只是很多东西没做过没这个胆而已。

论坛徽章:
0
10 [报告]
发表于 2007-03-11 00:08 |只看该作者
哈哈," 可能你用的少就不习惯吧", 仙子不用给我留面子,像flw直接指出来也挺好的。 我知道Perl上我还是门外汉。现在我的水平也就是停留在用C语言来写Perl的地步。不说了, 有版聊嫌疑, 晚安。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP