how to show nice file sizes

The rails extensions for bytes are found here

http://api.rubyonrails.org/classes/ActiveSupport/CoreExtensions/Numeric/Bytes.html

but they’re not really conversions. I think you would need to do some work to have it work nicely.

I thought this looked pretty interesting so I’ll give it a stab.
There is no doubt much nicer ways to do this though. Like
including it in the Numeric module or something.

Anyway… here goes.

I’m assuming that there is an array with abberviated units available as a constant BYTE_UNITS

[ “B”, “KB”, “MB”, “GB” etc] with the abbreviation set at an index such
that 1024 ** index will provide the correct unit. ie.

index = 0 => Byte

index = 1 => KB

etc

def format_nice_bytes( a_number )

index = ( Math.log( a_number ) / Math.log( 2 ) ).to_i / 10

“#{a_number.to_i / ( 1024 ** index ) } #{BYTE_UNITS[index]}”

end

Hope that works for you. (and that you can beutify it!!)

would work, but you would be feeding processor cycles to the hogs needlessly.

I am completely new to Ruby (Pythonista of many years), but I think something
like this would work and be some orders of magnitude faster (and easier to
read):

def format_nice_bytes(n)
        [[1073741824, "GB"], [1048576, "MB"], [1024, "KB"], [0, "B"]].each {|
u> if (n > u[0]) then return printf("%.2f %s",n/u[0], u[1]); end }
end

I am sure somebody more familiar with Ruby will come up with a far more
elegant and efficient solution
Horst

I do sometimes get carried away with open ended solutions…

Running a benchmark on the code (original method is 1, your suggestion is 2, and a modified version of your suggestion is 3) gives

format_nice_bytes1 0.031000 0.000000 0.031000 ( 0.032000)
format_nice_bytes2 0.110000 0.031000 0.141000 ( 0.234000)
format_nice_bytes3 0.062000 0.000000 0.062000 ( 0.063000)

But this doesn’t really mean much. There are two main differences that are super apparent to me with this one.

  1. each run through methods 2 and 3 had to create the array of units for every method call (very expensive)
  2. method 2 forced output to std out instead of just returning a string.

A refinement of taking the unit array out of the method into a constant so that it’s apples with apples on method 1 provides

format_nice_bytes1 0.031000 0.000000 0.031000 ( 0.031000)
format_nice_bytes2 0.110000 0.000000 0.110000 ( 0.234000)
format_nice_bytes3 0.047000 0.000000 0.047000 ( 0.047000)
format_nice_bytes4 0.031000 0.000000 0.031000 ( 0.031000)

There doesn’t look like there’s much in it between method 1 and 4, but 4 is easier to read. I haven’t done many benchmarks though so I’d be more than happy to have other feedback.

I’ve attached the test file that I used and listed the methods below.

BYTE_UNITS = [“B”, “KB”, “MB”, “GB” ]
BYTE_UNITS2 =[[1073741824, “GB”], [1048576, “MB”], [1024, “KB”], [0, “B”]]

def format_nice_bytes1( a_number )
index = ( Math.log( a_number ) / Math.log( 2 ) ).to_i / 10
“#{a_number.to_i / ( 1024 ** index ) } #{BYTE_UNITS[index]}”

end

def format_nice_bytes2(n)

   [[1073741824, "GB"], [1048576, "MB"], [1024, "KB"], [0, "B"]].each {|u| if (n > u[0]) then return printf("%.2f %s",n/u[0], u[1]); end }

end

def format_nice_bytes3(n)

   unit = [[1073741824, "GB"], [1048576, "MB"], [1024, "KB"], [0, "B"]].detect{ |u| n > u[0] }
   "#{n/unit[0]} #{unit[1]}"

end

def format_nice_bytes4(n)

unit = BYTE_UNITS2.detect{ |u| n > u[0] }
“#{n/unit[0]} #{unit[1]}”
end

tester.rb (1.33 KB)

I thought there might be one… It sure was fun though… :wink: