gri6507 has asked for the wisdom of the Perl Monks concerning the following question:

Hello,

After a recent discussion about programs that analyze an entire harddrive to graphically display the file distribution on the drive (we couldn't come up with any names), I decided to try one out for myself. The driving force behind me doing so was my curiosity to see what percentage of the drive is used up by MP3, MPEG, and other multimedia files. I wrote the program using File::Find and File::stat, and have questions on both of these.

Below is the code for this program. Many thanks for your wisdom in advance.

use strict; use warnings; use File::Find; use File::stat; use Tk; my @wanted_count; #sizes of desired file types my $other_count; #size of every other file type my $canvas_w = 300; #width of display my $canvas_h = 300; #height of display my $radius = 100; #radius of pie chart my $map = 15; #size of key map image my @color = qw(#FF0000 #00FF00 #0000FF #FF00FF #00FFFF #FFFF00); if ($#ARGV < 1){ print "Usage:$0 <initial dir> <list of extentions>\n"; print "If want to see *.mp3 files, then make extention mp3\n"; print "So far, this program can handle up to 5 extentions\n"; } foreach (@ARGV){ push(@wanted_count, 0); #init each file type } my $mw = MainWindow->new(-title=>"File Monitor", -width=>$canvas_w+180, -height=>$canvas_h+10); my $canvas = $mw->Canvas(-width=>$canvas_w, -height=>$canvas_h, -relief=>"sunken", -borderwidth=>2)->place(-x=>2,-y=>2); finddepth(\&wanted, shift @ARGV); my $total = sum($other_count, @wanted_count); my $last = 0; for (my $i=0; $i<$#wanted_count; $i++){ lookup($last, $i, $ARGV[$i], $wanted_count[$i]); $last += $wanted_count[$i]/$total*360; } lookup($last, $#ARGV+1, "Other", $other_count); MainLoop; sub lookup{ my ($start, $i, $caption, $value) = @_; $canvas->createArc($canvas_w/2-$radius,$canvas_h/2-$radius,$canvas_w +/2+$radius,$canvas_h/2+$radius, -start=>$start, -extent=>$value/$total*359.9, -fill=>$color[$i]); my $img = $mw->Photo('img' . $i, -width=>$map, -height=>$map); $img->put($color[$i], -to=>0,0,$map,$map); $mw->Label(-image=>'img' . $i, -relief=>"flat")->place(-x=>$canvas_w+10, -y=>$i*25); $mw->Label(-font=>"Arial 8", -text=>$caption . value($value))->place(-x=>$canvas_w+10+1.25 +*$map, -y=>$i*25); } sub value { my $out = " ("; my $order = 0; while ($_[0] > 1024){ $_[0] /= 1024; $order++; } $out = sprintf("%s %.3f ",$out,$_[0]); $out .= do { (!--$order) ? "k" : (!--$order) ? "M" : (!--$order) ? "G" : ""; }; return $out . "B)"; } sub sum{ my ($c,@d) = @_; foreach(@d){ $c += $_; } return $c; } sub wanted{ if (-d $File::Find::name){ return; } if (!-f $File::Find::name){ print "$File::Find::name does not exist\n"; return; } for(my $i=0;$i<=$#ARGV;$i++){ if (/\.$ARGV[$i]$/){ $wanted_count[$i] += stat($File::Find::name)->size; return; } } $other_count += stat($File::Find::name)->size; }

Edit by tye to add <readmore>

Replies are listed 'Best First'.
Re: Problems using File::stat,Find under windows
by metadoktor (Hermit) on Mar 21, 2002 at 17:31 UTC
    When I run the program (on a Windows box) looking for, say ".mp3" files, i get one answer for the total size of all files with mp3 extensions, but when I look for the "*.mp3" files in the windows search utility, I get a different (larger) answer. Is File::stat doing something wrong or am I not finding all mp3 files?

    IIRC, there is a difference between the actual size of a file and the amount of space it actually occupies. You may be running into this problem.

    If you've ever used TreeSize Professional you would have noticed that there is 'wasted' space that is taken up (allocated) by files but not actually used to store anything.

    metadoktor

    "The doktor is in."

Re: Problems using File::stat,Find under windows
by vladb (Vicar) on Mar 21, 2002 at 17:48 UTC
    Unfortunately, since I rarely (if ever) code Perl under Windows, I may not have an immediate advice to cure your problem. However, I still think you don't have to do the '-f' check inside your wanted subroutine. My thinking is that the file ($File::Find::name) should always exist, hence the reason it was found in the first place.

    As to why you are getting the "Can't call method 'size' on an undefined value" error, it seems as if the stat() function fails to obtain file statistics due to reasons such as certain file attributes (hidden, archive, etc.)? If you are working on WindowsNT there also might be some conflicting group/user permissions at play.

    To shield yourself from the error, you might consider adding this check:
    .... if (my $file_stat = stat($File::Find::name)) { $wanted_count[$i] += $file_stat->size; } else { print "Failed to obtain stats on file '$File::Find::name'"; } return; .....


    "There is no system but GNU, and Linux is one of its kernels." -- Confession of Faith
      you don't have to do the '-f' check inside your wanted subroutine. My thinking is that the file ($File::Find::name) should always exist,

      While you are mostly corrct about the file existing (although on a multiuser system it might have been deleted in the meantime) youve got the meaning of the -f filetest wrong. It returns true if the item in question is a file. And File::Find will match directories as well as files. So the meaning of this test in this case is to eliminate any found dirs.

      Yves / DeMerphq
      ---
      Writing a good benchmark isnt as easy as it might look.