Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

GB, MB, KB and on..

by cez (Novice)
on Jul 29, 2004 at 23:01 UTC ( [id://378538]=perlquestion: print w/replies, xml ) Need Help??

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

whats the most elegant/simple solution to print a filesize at the appropriate scale? for example, given x KB, turn that into x.xxMB, x.xxGB, x.xxKB, etc. i know this must be common, but everything I can think of is very clunky and ugly.

Replies are listed 'Best First'.
Re: GB, MB, KB and on..
by BrowserUk (Patriarch) on Jul 29, 2004 at 23:24 UTC

    #! perl -slw use strict; sub scaleIt { my( $size, $n ) =( shift, 0 ); ++$n and $size /= 1024 until $size < 1024; return sprintf "%.2f %s", $size, ( qw[ bytes KB MB GB ] )[ $n ]; } my $size = -s $ARGV[ 0 ]; print "$ARGV[ 0 ]: ", scaleIt $size; __END__ P:\test>for %f in (data\*) do @test1 %f data\10GB.dat: 9.77 GB data\10Mrand.dat: 85.83 MB data\10Mrand.pp: 0.00 bytes data\10Msort.p: 0.00 bytes data\10Msort.pp: 0.00 bytes data\1mb.dat: 1.06 MB data\1Mx16384.dat: 15.26 GB data\1Mx4096: 3.81 GB data\50mb.dat: 52.93 MB data\5mb.dat: 5.29 MB ...

    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail
    "Memory, processor, disk in that order on the hardware side. Algorithm, algoritm, algorithm on the code side." - tachyon
Re: GB, MB, KB and on..
by Joost (Canon) on Jul 29, 2004 at 23:26 UTC
    Take advantage of the fact that 1 Gb = 1024 Mb, 1 Mb = 1024 Kb and 1024 = 2 ** 10:
    my $kb = 1024 * 1024; # set to 1 Gb my $mb = $kb >> 10; my $gb = $mb >> 10; print "$kb kb = $mb mb = $gb gb\n"; __END__ 1048576 kb = 1024 mb = 1 gb
    Edit: after reading your post again, I'm afraid it doesn't really do what you want (though I think it's pretty elegant), because it will round down to the nearest integer.
Re: GB, MB, KB and on..
by cez (Novice) on Jul 29, 2004 at 23:30 UTC
    how about something like this?
    sub prettyBytes { my $size = $_[0]; foreach ('b','kb','mb','gb','tb','pb') { return sprintf("%.2f",$size)."$_" if $size < 1024; $size /= 1024; } }
        tell me i'm beautiful like you mean it.. :)

        i actually wrote that after i posed the question. its better than what i first tried.

        i'm still curious how other people would solve this, curiosity's sake!

      Fix if size is larger than PB. <code> sub prettyBytes { my $size = $_[0]; foreach ('b','kb','mb','gb','tb','pb') { last if $size < 1024; $size /= 1024; } return sprintf("%.2f",$size)."$_"; } <code>

        This does not work as expected as the value of $_ is undefined outside of the loop.

Re: GB, MB, KB and on..
by ysth (Canon) on Jul 30, 2004 at 03:26 UTC
    sub scaledbytes { (sort { length $a <=> length $b } map { sprintf '%.3g%s', $_[0]/1024**$_->[1], $_->[0] } [" bytes"=>0],[KB=>1],[MB=>2],[GB=>3],[TB=>4],[PB=>5],[EB=>6])[0] }
    Update: don't need none of those stinkin' semicolons. Feels kind of funny to use %g but filter out all the exponential forms (unless that's all there are).

      Different :)

      One interesting side effect of the sort is that zero length files get listed as 0KB rather than 0 bytes.


      Examine what is said, not who speaks.
      "Efficiency is intelligent laziness." -David Dunham
      "Think for yourself!" - Abigail
      "Memory, processor, disk in that order on the hardware side. Algorithm, algoritm, algorithm on the code side." - tachyon
Re: GB, MB, KB and on..
by Stevie-O (Friar) on Jul 30, 2004 at 00:33 UTC
    # will need adjustment if you want to do negative values # kbstring(1024) => 1KB # MS uses a threshold of 0.98. I find this to be a perfectly # acceptable threshold. 0.98*1024 == 1003. sub kbstring { my $value = shift; my @prefix = ('', qw(K M G T)); while (@prefix>1 && $value >= 1000) { shift @prefix; $value /= 1024; } return sprintf '%.2fdsB', $value, $prefix[0]; }
    --Stevie-O
    $"=$,,$_=q>|\p4<6 8p<M/_|<('=> .q>.<4-KI<l|2$<6%s!<qn#F<>;$, .=pack'N*',"@{[unpack'C*',$_] }"for split/</;$_=$,,y[A-Z a-z] {}cd;print lc
Re: GB, MB, KB and on..
by shenme (Priest) on Jul 30, 2004 at 01:17 UTC
    I was going to clean this up this recent code of mine (a lot! It's ugly!!) before posting, but that'd be awhile to find the time (this is from last weekend), and you asked, so... Also, I hadn't yet searched through the code posted on PM - I really wonder if this hasn't been done better elsewhere. (Not in any CPAN modules that I can find, though)

    I really wanted to handle quite large values, like some that are up into terabytes in just six months, and so I felt I needed to be able to handle large integers ala Math::BigInt. And I wanted to be able to handle the "K is 1000" vs. the "K is 1024" people. And I wanted to be able to reliably fit the output into a limited number of columns. Thus the following contortions...

    --
    I'm a pessimist about probabilities; I'm an optimist about possibilities.
    Lewis Mumford

Re: GB, MB, KB and on..
by cez (Novice) on Jul 29, 2004 at 23:32 UTC
    didn't see replies-- interesting solutions. thanks guys. I'll go play around some more.
Re: GB, MB, KB and on..
by Wassercrats (Initiate) on Jul 29, 2004 at 23:12 UTC
    Simply dividing two numbers is ugly to you? There are 1024 bytes in a KB. Divide by 1000 to get MB. Divide MB by 1000 to get GB.

    edit...I mean divide by 1024

      Divide by 1000? Are you selling disk drives? :-)

      There is some debate about whether it's 1000 or 1024 but you should be consistent, whichever you choose. So if you have 1024B in a KB then you should have 1024KB in an MB and 1024 MB in a GB.

      There is(was?) a proposal that since kilo and mega and giga already mean 10^3, 10^6 and 10^9 in all other fields that they should also mean that in computers and that we should say kibibyte, mebibyte and gigibyte (gibibyte?) when we're talking about the 1024 based versions. Needless to say this didn't catch on.

      As for the original question, something like this would do the trick. I leave it as an excercise to fix the fact that 25 bytes comes out as 25.000B

      my @sizes=qw( B KB MB GB TB PB); sub nice_size { my $size = shift; my $i = 0; while ($size > 1024) { $size = $size / 1024; $i++; } return sprintf("%.3f$sizes[$i]", $size); }
        There is some debate about whether it's 1000 or 1024

        The SI units for these two multiples have been standardised. See, for instance: Prefixes for binary multiples. The 1000 multiple gets to keep the K, M, G prefixes (in line with existing physical units like metres and ohms that we are used to representing in terms of thousands).

        For the 1024 multiple, the official term is binary: kilobinary, megabinary, yottabinary... abbreviated to KiB, MiB, GiB... YiB.

        The real push for making the distinction didn't come from the disk drive world. The impetus came from the telecommunications field, where bitrates are commonly expressed in terms of thousand bits per second, not 1024. This is where the most confusion arose: telecom engineers talking to software developers didn't agree on what K meant.

        - another intruder with the mooring of the heat of the Perl

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://378538]
Approved by eric256
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others rifling through the Monastery: (6)
As of 2024-04-23 23:18 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found