http://www.perlmonks.org?node_id=748644

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

I'm trying to print out all the directories and their sizes using the script below but I'm not getting correct results (I got some advice from http://www.mail-archive.com/beginners@perl.org/msg99758.html). For example it says that my C:/Perl/etc directory is 15.32 mb but Win Explorer folder properties says that it's 372 kb. I'm using Win XP and the script like this
C:\Perl\>perl Print_dirs.pl "C:/Perl/"
Where is the error, can you help me?
#!/bin/perl use warnings; use strict; use File::Find; my $path = $ARGV[0]; die "You must supply a full directory path" unless (-e $path && -d $pa +th); opendir (DIR, $path) or die "can't opendir $path: $!"; my @directories = grep { -d "$path/$_" && ! /^\./ } readdir(DIR); my $total_size_of_files_in_dir; foreach my $dir (@directories) { find(\&wanted, "$path/$dir"); ### Not sure how that worked a +s you called it $directory print "The total size of the file in $dir is " . sprintf("%.2f + Kb", ($total_size_of_files_in_dir * 0.0009765625)) . "\n"; print "The total size of the file in $dir is " . sprintf("%.2f + Mb", ($total_size_of_files_in_dir * 9.5367431641e-7)) . "\n"; print "The total size of the file in $dir is " . sprintf("%.2f + Mb", (&size_in_mb($total_size_of_files_in_dir))) . "\n"; } sub wanted { if (-f $_) { $total_size_of_files_in_dir += -s; } } sub size_in_mb { my $size_in_bytes = shift; return $size_in_bytes / (1024 * 1024); }

Replies are listed 'Best First'.
Re: Dir size
by shmem (Chancellor) on Mar 05, 2009 at 20:07 UTC

    Looks like your $total_size_of_files_in_dir is accumulating. Reset it at the end of the for loop.

      Better yet, avoid the global entirely.
      #!/usr/bin/perl use strict; use warnings; use File::Find qw( find ); my ($path) = @ARGV or die("usage: perl dir_size.pl dirpath\n"); opendir(my $dh, $path) or die("Can't open dir $path: $!\n"); while (defined(my $dir = readdir($dh)) { next if $dir =~ /^\./; my $full_dir = "$path/$subdir"; next if ! -d $full_dir; my $total = 0; find(sub { $total += -s if -f $_ }, $full_dir); print "The total size of the files in $dir is " . sprintf("%.2f Kb", ($total/1024)) . "\n"; print "The total size of the files in $dir is " . sprintf("%.2f Mb", ($total/(1024*1024))) . "\n"; }

      I don't know why people use a named sub for find. If I did want to split out the logic into a separate sub, I'd do something like

      sub some_sub { my @results; find(sub { push @results, $_ if check($_) }); ... } sub check { ... Check if the file matches. Doesn't know about File::Find ... }
      Wow! Thank you very much!!!
Re: Dir size
by GrandFather (Saint) on Mar 05, 2009 at 22:57 UTC
Re: Dir size
by Tanktalus (Canon) on Mar 05, 2009 at 21:52 UTC
Re: Dir size
by satanicpuppy (Novice) on Mar 05, 2009 at 22:56 UTC
    You can try using Win32::File instead of File::Find, for starters. Otherwise, windows being windows, if you want to know what size IT thinks a directory is, might as well ask it:
    $temp = `Dir $your_directory_here`; if($temp =~ m/(\s+)(\d+)( File)(\S{3})(\s+)(\S+)( bytes)/i){ print "$6 bytes\n"; }
    That's some ugly code. Works though, least in XP. YMMV, and it won't give you sizes on subdirectories. The regex is a bit more brittle than I'd like...It'd be cleaner if you ripped all the /'s and ,'s out of the directory output first. Then you'd probably be safe just doing:
    ... if($temp =~ m/(\s+)(\d+)( bytes)/i){ ...
      if you use "Dir /-C" it'll drop the commas.
Re: Dir size
by Discipulus (Canon) on Mar 06, 2009 at 08:56 UTC
    search first my friend! I have found this How do I recursively process files through directories, one of my first (newbiest's) contribution..

    if you are in a win32 env i found that the following code is very much faster:
    sub get_dir_size { my $root = shift; return 'NOT EXISITING FOLDER' unless -e $root; my $fs = Win32::OLE->CreateObject('Scripting.FileSystemObject'); my $folder = $fs->GetFolder($root); my $dimensione = $folder->size(); $fs = undef; return $dimensione; }
    HtH Lor*