-- lua-filesize, generate a human readable string describing the file size
-- See the LICENSE file for terms of use:
-- https://github.com/starius/lua-filesize/blob/master/LICENSE
-- AUTHORS: Boris Nagaev, Jason Xu
local si = {
base10 = {
bits = { "b", "Kb", "Mb", "Gb", "Tb", "Pb", "Eb", "Zb", "Yb" },
bytes = { "B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" }
},
base2 = {
bits = { "b", "Kib", "Mib", "Gib", "Tib", "Pib", "Eib", "Zib", "Yib" },
bytes = { "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB" }
} -- see https://docs.ukcloud.com/articles/other/other-ref-gib.html
}
local function isNan(num)
-- http://lua-users.org/wiki/InfAndNanComparisons
-- NaN is the only value that doesn't equal itself
return num ~= num
end
local function roundNumber(num, digits)
local fmt = "%." .. digits .. "f"
return tonumber(fmt:format(num))
end
local function filesize(size, options)
-- copy options to o
local o = {}
for key, value in pairs(options or {}) do
o[key] = value
end
local function setDefault(name, default)
if o[name] == nil then
o[name] = default
end
end
setDefault("bits", false)
setDefault("unix", false)
setDefault("base", 2)
setDefault("round", o.unix and 1 or 2)
setDefault("spacer", o.unix and "" or " ")
setDefault("suffixes", {})
setDefault("output", "string")
setDefault("exponent", -1)
assert(not isNan(size), "Invalid arguments")
local ceil = (o.base > 2) and 1000 or 1024
local negative = (size < 0)
if negative then
-- Flipping a negative number to determine the size
size = -size
end
local result
-- Zero is now a special case because bytes divide by 1
if size == 0 then
result = {
0,
o.unix and "" or (o.bits and "b" or "B")
}
else
-- Determining the exponent
if o.exponent == -1 or isNan(o.exponent) then
o.exponent = math.floor(math.log(size) / math.log(ceil))
end
-- Exceeding supported length, time to reduce & multiply
if o.exponent > 8 then
o.exponent = 8
end
local val
if o.base == 2 then
val = size / math.pow(2, o.exponent * 10)
else
val = size / math.pow(1000, o.exponent)
end
if o.bits then
val = val * 8
if val > ceil then
val = val / ceil
o.exponent = o.exponent + 1
end
end
result = {
roundNumber(val, o.exponent > 0 and o.round or 0),
(o.base == 10 and o.exponent == 1) and (o.bits and "kb" or "kB") or
(si[o.base == 2 and "base2" or "base10"][o.bits and "bits" or "bytes"][o.exponent + 1])
}
if o.unix then
result[2] = result[2]:sub(1, 1)
if result[2] == "b" or result[2] == "B" then
result = {
math.floor(result[1]),
""
}
end
end
end
assert(result)
-- Decorating a 'diff'
if negative then
result[1] = -result[1]
end
-- Applying custom suffix
result[2] = o.suffixes[result[2]] or result[2]
-- Applying custom suffix
result[2] = o.suffixes[result[2]] or result[2]
-- Returning Array, Object, or String (default)
if o.output == "array" then
return result
elseif o.output == "exponent" then
return o.exponent
elseif o.output == "object" then
return {
value = result[1],
suffix = result[2]
}
elseif o.output == "string" then
local value = tostring(result[1])
value = value:gsub("%.0$", "")
local suffix = result[2]
return value .. o.spacer .. suffix
end
end
return filesize