-- 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