免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12
最近访问板块 发新帖
楼主: cooldog
打印 上一主题 下一主题

perl如何获取一个目录中所有文件的大小总和 [复制链接]

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
11 [报告]
发表于 2008-12-12 08:00 |只看该作者
原帖由 smzml 于 2006-3-19 16:34 发表
谢谢5楼大哥。但是这样只能统计某个目录下的文件,如果有子目录和子文件,它数不出来呀。
而且,如果文件有几千个,统计效率好象很慢,有没有快一点的办法呀?

不管你用啥方法,其实都是递归遍历,只不过有些实现的效率比较高,有些比较低而已。

论坛徽章:
0
12 [报告]
发表于 2008-12-12 10:52 |只看该作者
我前几天恰好写过一个类似的东西,http://www.icylife.net/yunshu/show.php?id=647

  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use threads;
  5. use threads::shared;
  6. use Thread::Semaphore;

  7. my ($size, $dircnt, $filecnt) = (0, 0, 0);
  8. my %size_hash : shared;
  9. my @sub_dirs;

  10. if( @ARGV != 3 )
  11. {
  12.         print "usage: $0  <rootdir>   <depth>   <topn> \n";
  13.         print "example:$0   c:\\    3   15\n";

  14.         exit;
  15. }
  16. my $root = $ARGV[0];
  17. my $sub = $ARGV[1];
  18. my $topn = $ARGV[2];

  19. if( $root !~ /\\$/ && $root !~ /\/$/ )
  20. {
  21.         $root = $root."\\";
  22. }

  23. print "开始搜寻$root下面的$sub级子目录.....\n";
  24. &GetSubDirectory( );

  25. print "开始获取目录大小......\n";
  26. my $max_thread_count = 100;
  27. my $semaphore = new Thread::Semaphore( $max_thread_count );
  28. foreach my $tmp_dir( @sub_dirs )
  29. {
  30.         $semaphore->down( );
  31.         my $thread = threads->create( \&GetDirectorySize, $tmp_dir );
  32.         $thread->detach();
  33. }

  34. &Wait2Quit( );

  35. my $index = 0;
  36. foreach my $key ( sort { $size_hash{$b} <=> $size_hash{$a} } keys %size_hash)
  37. {
  38.         if( $index == $topn )
  39.         {
  40.                 last;
  41.         }
  42.         printf( "%-50s%18s 字节\n", $key, $size_hash{$key} );
  43.         $index ++;
  44. }

  45. sub Wait2Quit
  46. {
  47.         my $num = 0;
  48.         while( $num < $max_thread_count )
  49.         {
  50.                 # 尝试获取信号量,当能够获取到最大线程数个信号量时,表示所有线程都结束了
  51.                 $semaphore->down( );
  52.                 $num ++;
  53.         }
  54.         #print "All $max_thread_count thread quit\n";
  55. }

  56. sub GetSubDirectory
  57. {
  58.         my @dirs;
  59.         push( @dirs, $root );

  60.         my ( $current_dir, $file );
  61.         while ( $current_dir = pop(@dirs) )
  62.         {
  63.                 # 根据路径中\或者/的次数,确定当前是几级目录
  64.                 #print "processing $current_dir:";
  65.                 my $sub_count = 0;
  66.                 while( $current_dir=~/\\|\//g )
  67.                 {
  68.                         $sub_count++;
  69.                 }
  70.                 #print " $sub_count\n";
  71.                 # 等于指定深度的,加入到最终数组中
  72.                 if( $sub_count == $sub )
  73.                 {
  74.                         #print $current_dir."\n";
  75.                         push( @sub_dirs, $current_dir );
  76.                         next;
  77.                 }
  78.                 # 过深的目录不予处理
  79.                 elsif( $sub_count > $sub )
  80.                 {
  81.                         next;
  82.                 }

  83.                 # 目录结尾加上\
  84.                 if( $current_dir !~ /\\$/ && $current_dir !~ /\/$/ )
  85.                 {
  86.                         $current_dir = $current_dir."\\";
  87.                 }

  88.                 # 路径不足的打开目录,查找子目录
  89.                 local *DH;
  90.                 if ( !opendir(DH, $current_dir) )
  91.                 {
  92.                         #print "Cannot opendir $current_dir: $!\n";
  93.                         next;
  94.                 }

  95.                 # 读取文件和子目录列表
  96.                 foreach( readdir(DH) )
  97.                 {
  98.                         # 当前目录和上级目录跳过
  99.                         if ($_ eq "." || $_ eq "..")
  100.                         {
  101.                                 next;
  102.                         }
  103.                         $file = $current_dir.$_;
  104.                         if ( !-l $file && -d $file )
  105.                         {
  106.                                 #print "Add $file\n";
  107.                                 push(@dirs, $file);
  108.                         }
  109.                         #&process($file);
  110.                 }
  111.                 closedir(DH);
  112.         }
  113. }

  114. sub GetDirectorySize
  115. {
  116.         my $first_dir = shift;
  117.         $size_hash{ $first_dir } = 0;

  118.         my @dirs;
  119.         push( @dirs, $first_dir );

  120.         my ( $current_dir, $file );
  121.         while ( $current_dir = pop(@dirs) )
  122.         {
  123.                 # 目录结尾加上\
  124.                 if( $current_dir !~ /\\$/ && $current_dir !~ /\/$/ )
  125.                 {
  126.                         $current_dir = $current_dir."\\";
  127.                 }

  128.                 # 打开目录,查找子目录以及文件
  129.                 local *DH;
  130.                 if ( !opendir(DH, $current_dir) )
  131.                 {
  132.                         #print "Cannot opendir $current_dir: $!\n";
  133.                         next;
  134.                 }

  135.                 # 读取文件和子目录列表
  136.                 foreach( readdir(DH) )
  137.                 {
  138.                         # 当前目录和上级目录跳过
  139.                         if ($_ eq "." || $_ eq "..")
  140.                         {
  141.                                 next;
  142.                         }
  143.                        
  144.                         # 形成绝对路径
  145.                         $file = $current_dir.$_;

  146.                         # 处理目录或符号链接
  147.                         if ( !-l $file && -d $file )
  148.                         {
  149.                                 push(@dirs, $file);
  150.                         }
  151.                        
  152.                         $size_hash{ $first_dir } += -s $file;
  153.                 }
  154.                 closedir(DH);
  155.         }

  156.         $semaphore->up( );
  157. }
复制代码

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
13 [报告]
发表于 2008-12-12 11:08 |只看该作者

回复 #12 撒哈拉里的鱼 的帖子

你为啥不用 File::Find?

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
14 [报告]
发表于 2008-12-12 11:14 |只看该作者
原帖由 flw 于 2008-12-12 11:08 发表
你为啥不用 File::Find?

遍历目录用这个很方便

论坛徽章:
0
15 [报告]
发表于 2008-12-12 13:29 |只看该作者
因为对比过,File::Find没有我自己写的速度快。

论坛徽章:
0
16 [报告]
发表于 2008-12-12 13:35 |只看该作者
原帖由 flw 于 2008-12-12 11:08 发表
你为啥不用 File::Find?



遍历目录的话,File_Find 模块的确不方便,正常情况下,用stat函数获得每个文件的大小,但是在累加求和的时候,发现每次都要去调用wanted子过程,不是多方便。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP