1/**
2 * Format bytes as human-readable text.
3 *
4 * @param bytes Number of bytes.
5 * @param si True to use metric (SI) units, aka powers of 1000. False to use
6 * binary (IEC), aka powers of 1024.
7 * @param dp Number of decimal places to display.
8 *
9 * @return Formatted string.
10 */
11export function humanFileSize(bytes: number, si: boolean = false, dp: number = 1) {
12 const thresh = si ? 1000 : 1024
13
14 if (Math.abs(bytes) < thresh) {
15 return bytes + ' B'
16 }
17
18 const units = si
19 ? ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
20 : ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']
21 let u = -1
22 const r = 10 ** dp
23
24 do {
25 bytes /= thresh
26 ++u
27 } while (Math.round(Math.abs(bytes) * r) / r >= thresh && u < units.length - 1)
28
29 return bytes.toFixed(dp) + ' ' + units[u]
30}