Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations John Tel on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

converting between bytes/kb/mb/gb

Status
Not open for further replies.

cgilover

Programmer
Oct 8, 2004
32
US
I have a script that calculates file sizes per file extension. The first part is the sum of all files in that extension, the second part is the average size (deprived from the total number of files in that extension and the total size).

The problems I am having is converting the bytes into more practical units (the biggest whole unit).

The $file_size works perfectly! The output looks great. A sample of the output is:

Code:
Extension    Number of files     Size of extension  
txt          7158                46.74 MB 
AVG          31                  87.80 KB
tlx          38                  624.77 KB
swf          361                 25.70 MB


The $avg_size which uses the exact same idea and logic as $file_size does NOT work for some reason! This is what I need help debugging.

The same output as above but with the avg_size:
Code:
Extension    Number of files     Size of extension     Average size  
txt          7158                46.74 MB         0.05 KB 
AVG          31                  87.80 KB         0.09 KB 
tlx          38                  624.77 KB        0.61 KB 
swf          361                 25.70 MB         0.03 KB

As you can see, for txt it says the average size is 0.05 KB. If infact this is correct, it's not a whole unit so I want it pushed back into bytes.

If it's like .9 MB or .05 GB or whatever, I need it pushed back into XX KB and XX MB and such.

Any idea how I can fix this?


The source code:
Code:
 if ($file_size < 1024)
    {
       print FILE "<td>$file_size bytes</td>";
    }
    elsif ($file_size >= 1024 && $file_size < 1024 * 1024)
    {
       $file_size = $file_size / 1024;
       $file_size = sprintf("%.2f",$file_size);
       print FILE "<td>$file_size KB</td>";
    }
    elsif ($file_size >= 1024 * 1024 && $file_size < 1024 * 1024 * 1024)
    {
       $file_size = $file_size / (1024 * 1024);
       $file_size = sprintf("%.2f",$file_size);
       print FILE "<td>$file_size MB</td>";
    }
    elsif ($file_size >= 1024 * 1024 * 1024)
    {
       $file_size = $file_size / (1024 * 1024 * 1024) ;
       $file_size = sprintf("%.2f",$file_size);
       print FILE "<td>$file_size GB</td>";
    }

    #########################################################

    if ($avg_size < 1024)
    {
       print FILE "<td>$avg_size bytes</td>";
    }
    elsif ($avg_size >= 1024 && $avg_size < 1024 * 1024)
    {
       $avg_size = $file_size / 1024;
       $avg_size = sprintf("%.2f",$avg_size);
       print FILE "<td>$avg_size KB</td>";
    }
    elsif ($avg_size >= 1024 * 1024 && $avg_size < 1024 * 1024 * 1024)
    {
       $avg_size = $avg_size / (1024 * 1024);
       $avg_size = sprintf("%.2f",$avg_size);
       print FILE "<td>$avg_size MB</td>";
    }
    elsif ($avg_size >= 1024 * 1024 * 1024)
    {
       $avg_size = $avg_size / (1024 * 1024 * 1024);
       $avg_size = sprintf("%.2f",$avg_size);
       print FILE "<td>$avg_size GB</td>";
    }


Thanks!

 
I've got a feeling that the average size isn't calculated correctly

Could you post the code related to that

OR it could be this puppy
Code:
elsif ($avg_size >= 1024 && $avg_size < 1024 * 1024)
    {
       $avg_size = [b][COLOR=red]$file_size[/color][/b] / 1024;
       $avg_size = sprintf("%.2f",$avg_size);
       print FILE "<td>$avg_size KB</td>";
    }

HTH
--Paul

Nancy Griffith - songstress extraordinaire,
and composer of the snipers anthem "From a distance ...
 
cgilover

Refactor your code to help you to see the wood from the trees. Move the formatting to a subroutine, something like
Code:
use strict;

sub file_size {
   my $size = shift(@_);

   if ($size < 1024) {
      return $size . " bytes";
   }
   if ($size < (1024*1024)) {
      return sprintf("%.2f",$size / 1024) . " KB";
   }
   if ($size < (1024*1024*1024)) {
      return sprintf("%.2f",$size / (1024*1024)) . " MB";
   }
   return sprintf("%.2f",$size / (1024*1024*1024)) . " GB";
}

# check it out

my $ext = "txt";
my $size = 46000000;
my $count = 7158;

print "<TR><TD>$ext</TD><TD>", file_size($size), "</TD><TD>", file_size($size/$count), "</TD></TR>\n";
This then automatically uses the correct order of magnitude no matter what value you pass it. And assuming that the value in $count is correct, it should fix your averaging problem too, as all calculations are done with 'full-sized' values. And if it ever needs to be upgraded to deal with terabytes, we only have to add another 'if' statement...

HTH

Steve
 
Also, while I'm on about refactoring, let's give the subroutine a more descriptive name to make it self-documenting, and use sprintf properly too...
Code:
use strict;

sub size_fmt {
   my $size = shift(@_);

   if ($size < 1024) {
      return $size . " bytes";
   }
   if ($size < (1024*1024)) {
      return sprintf("%.2f KB",$size / 1024);
   }
   if ($size < (1024*1024*1024)) {
      return sprintf("%.2f MB",$size / (1024*1024));
   }
   return sprintf("%.2f GB",$size / (1024*1024*1024));
}

# check it out

my $ext = "txt";
my $size = 46000000;
my $count = 7158;

print "<TR><TD>$ext</TD><TD>", size_fmt($size), "</TD><TD>", size_fmt($size/$count), "</TD></TR>\n";
 
cgilover

Your first elsif block for your average uses:

Code:
elsif ($avg_size >= 1024 && $avg_size < 1024 * 1024)
    {
       $avg_size = $file_size / 1024;
       $avg_size = sprintf("%.2f",$avg_size);
       print FILE "<td>$avg_size KB</td>";

instead of:
Code:
elsif ($avg_size >= 1024 && $avg_size < 1024 * 1024)
    {
       $avg_size = $avg_size / 1024;
       $avg_size = sprintf("%.2f",$avg_size);
       print FILE "<td>$avg_size KB</td>";

Notice I have changed $file_size to $avg_size in the division statement.


Michael Libeson
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top