首页 > 计算机应用 > Perl深度优先获取指定目录下指定深度的子目录大小top n

Perl深度优先获取指定目录下指定深度的子目录大小top n

摘要:有时候硬盘空间不够,不过不知道是被什么东西占用了。恰好前几天一个同事又提到过这个事情,我就用perl做了个脚本,最后用pdk编译成exe给他用了用,感觉还行。我没有使用File::Find模块,因为这东西虽然简单但是速度稍微差了一点。

查找指定深度的目录,通过把perl中的数组当成栈来实现的深度优先查找。这一步不是很废时间,因此没有多线程。第二步获取查找出来的目录大小,每个目录 的深度不同,文件数量也难以预先判定,所以使用了多线程去计算文件大小累加。最后的等待退出,使用的我曾经写过《在perl中使用信号量等待detach 后的线程》中的方法。

代码不复杂,但是很烦,有很大一部分重复代码,我也懒得去重复利用什么的了,就这么着吧。

复制内容到剪贴板程序代码程序代码
#!/usr/bin/perl
use strict;
use warnings;
use threads;
use threads::shared;
use Thread::Semaphore;
my ($size, $dircnt, $filecnt) = (0, 0, 0);
my %size_hash : shared;
my @sub_dirs;
if( @ARGV != 3 )
{
print "usage:         \n";
print "example:   c:\    3   15\n";
exit;
}
my $root = $ARGV[0];
my $sub = $ARGV[1];
my $topn = $ARGV[2];
if( $root !~ /\$/ && $root !~ /\/$/ )
{
$root = $root."\";
}
print "开始搜寻$root下面的$sub级子目录…..\n";
&GetSubDirectory( );
print "开始获取目录大小……\n";
my $max_thread_count = 100;
my $semaphore = new Thread::Semaphore( $max_thread_count );
foreach my $tmp_dir( @sub_dirs )
{
$semaphore->down( );
my $thread = threads->create( \&GetDirectorySize, $tmp_dir );
$thread->detach();
}
&Wait2Quit( );
my $index = 0;
foreach my $key ( sort { $size_hash{$b} <=> $size_hash{$a} } keys %size_hash)
{
if( $index == $topn )
{
last;
}
printf( "%-50s%18s 字节\n", $key, $size_hash{$key} );
$index ++;
}
sub Wait2Quit
{
my $num = 0;
while( $num < $max_thread_count )
{
# 尝试获取信号量,当能够获取到最大线程数个信号量时,表示所有线程都结束了
$semaphore->down( );
$num ++;
}
#print "All $max_thread_count thread quit\n";
}
sub GetSubDirectory
{
my @dirs;
push( @dirs, $root );
my ( $current_dir, $file );
while ( $current_dir = pop(@dirs) )
{
# 根据路径中\或者/的次数,确定当前是几级目录
#print "processing $current_dir:";
my $sub_count = 0;
while( $current_dir=~/\|\//g )
{
$sub_count++;
}
#print " $sub_count\n";
# 等于指定深度的,加入到最终数组中
if( $sub_count == $sub )
{
#print $current_dir."\n";
push( @sub_dirs, $current_dir );
next;
}
# 过深的目录不予处理
elsif( $sub_count > $sub )
{
next;
}
# 目录结尾加上\
if( $current_dir !~ /\$/ && $current_dir !~ /\/$/ )
{
$current_dir = $current_dir."\";
}
# 路径不足的打开目录,查找子目录
local *DH;
if ( !opendir(DH, $current_dir) )
{
#print "Cannot opendir $current_dir: $!\n";
next;
}
# 读取文件和子目录列表
foreach( readdir(DH) )
{
# 当前目录和上级目录跳过
if ($_ eq "." || $_ eq "..")
{
next;
}
$file = $current_dir.$_;
if ( !-l $file && -d $file )
{
#print "Add $file\n";
push(@dirs, $file);
}
#&process($file);
}
closedir(DH);
}
}
sub GetDirectorySize
{
my $first_dir = shift;
$size_hash{ $first_dir } = 0;
my @dirs;
push( @dirs, $first_dir );
my ( $current_dir, $file );
while ( $current_dir = pop(@dirs) )
{
# 目录结尾加上\
if( $current_dir !~ /\$/ && $current_dir !~ /\/$/ )
{
$current_dir = $current_dir."\";
}
# 打开目录,查找子目录以及文件
local *DH;
if ( !opendir(DH, $current_dir) )
{
#print "Cannot opendir $current_dir: $!\n";
next;
}
# 读取文件和子目录列表
foreach( readdir(DH) )
{
# 当前目录和上级目录跳过
if ($_ eq "." || $_ eq "..")
{
next;
}
# 形成绝对路径
$file = $current_dir.$_;
# 处理目录或符号链接
if ( !-l $file && -d $file )
{
push(@dirs, $file);
}
$size_hash{ $first_dir } += -s $file;
}
closedir(DH);
}
$semaphore->up( );
}

转载请尊重版权,出处:秋天博客
本文链接: https://www.cfresh.net/pc-tech/492

  1. 还没有评论
评论提交中, 请稍候...

留言



注意: 您给他人的评论回复将通过邮件通知到对方。

可以使用的标签: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>
Trackbacks & Pingbacks ( 0 )
  1. 还没有 trackbacks