470

I got this code to covert size in bytes via PHP.

Now I want to convert those sizes to human readable sizes using JavaScript. I tried to convert this code to JavaScript, which looks like this:

function formatSizeUnits(bytes){
  if      (bytes >= 1073741824) { bytes = (bytes / 1073741824).toFixed(2) + " GB"; }
  else if (bytes >= 1048576)    { bytes = (bytes / 1048576).toFixed(2) + " MB"; }
  else if (bytes >= 1024)       { bytes = (bytes / 1024).toFixed(2) + " KB"; }
  else if (bytes > 1)           { bytes = bytes + " bytes"; }
  else if (bytes == 1)          { bytes = bytes + " byte"; }
  else                          { bytes = "0 bytes"; }
  return bytes;
}

Is this the correct way of doing this? Is there an easier way?

l2aelba
  • 21,591
  • 22
  • 102
  • 138

34 Answers34

1260

From this: (source)


Unminified and ES6'ed: (by the community)

function formatBytes(bytes, decimals = 2) {
    if (!+bytes) return '0 Bytes'

    const k = 1024
    const dm = decimals < 0 ? 0 : decimals
    const sizes = ['Bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']

    const i = Math.floor(Math.log(bytes) / Math.log(k))

    return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`
}

// Demo code
document.body.innerHTML += `<input type="text" oninput="document.querySelector('p').innerHTML=formatBytes(this.value)" value="1000"><p>1000 Bytes</p>`

Minified version (by StackOverflow's community, minified by JSCompress)

function formatBytes(a,b=2){if(!+a)return"0 Bytes";const c=0>b?0:b,d=Math.floor(Math.log(a)/Math.log(1024));return`${parseFloat((a/Math.pow(1024,d)).toFixed(c))} ${["Bytes","KiB","MiB","GiB","TiB","PiB","EiB","ZiB","YiB"][d]}`}

Usage:

// formatBytes(bytes, decimals)

formatBytes(1024)       // 1 KiB
formatBytes('1024')     // 1 KiB
formatBytes(1234)       // 1.21 KiB
formatBytes(1234, 3)    // 1.205 KiB
formatBytes(0)          // 0 Bytes
formatBytes('0')        // 0 Bytes

PS : Change k = 1000 or sizes = ["..."] as you want (bits or bytes)

Andrey Izman
  • 1,807
  • 1
  • 24
  • 27
  • 11
    (1) why bytes = 0 is "n/a"? Isn't it just "0 B"? (2) Math.round doesn't have precision parameter. I'd better use `(bytes / Math.pow(1024, i)).toPrecision(3)` – disfated Sep 21 '13 at 15:50
  • A see two problems: First: values f.ex 1000. It returns 1.00e+3. This can be fixed with this: `Number((bytes / Math.pow(k, i)).toPrecision(3)) + ' ' + sizes[i];`. Second: values like 0.7. Logarithm returns negative value. It can be fixed with this: `if(bytes < 1) return '0 B';` – Ajax Oct 17 '14 at 17:40
  • Works nice ! there is another issue when approaching 1GB or 1TB values, it will show you 1000 MB or 1000GB instead, due to the approximation. a little fix is to add this before the last line : `if(String((bytes / Math.pow(k, i)).toFixed(0)).length === 4){i++;}` As @Ajax said, there is an issue with numbers returned as 1.00e+3. I would suggest to use `toFixed(x)` instead of `toPrecision(x)` to fix the number of decimals. `toPrecision(x)` define the total characters of your value. (that's where the 1.00e+3 comes from, since it cant write 1000, with a precision of 3.) – hereismass Feb 12 '15 at 15:20
  • 4
    `toFixed(n)` is probably more appropriate than `toPrecision(n)` to have a consistant precision for all the values. And to avoid trailing zeros (ex: `bytesToSize(1000) // return "1.00 KB"`) we could use `parseFloat(x)`. I suggest to replace the last line by: `return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];`. With the previous change the results are: `bytesToSize(1000) // return "1 KB"` / `bytesToSize(1100) // return "1.1 KB"` / `bytesToSize(1110) // return "1.11 KB` / `bytesToSize(1111) // also return "1.11 KB"` – MathieuLescure Mar 25 '15 at 15:19
  • Need correction: to handle -ve Math.floor(Math.log(Math.abs(bytes)) – jaaw Dec 22 '15 at 01:33
  • `999999999999999999999999990` returns `1 undefined` – Slava Mar 19 '16 at 13:42
  • @Alph.Dev add your more `var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];` – l2aelba Apr 05 '16 at 19:41
  • 4
    I believe plural form is used for 0: '0 Bytes' – nima May 05 '16 at 09:41
  • Just a tiny modification: add radix value 10 to `parseInt` — "Always specify this parameter to eliminate reader confusion and to guarantee predictable behavior. Different implementations produce different results when a radix is not specified, usually defaulting the value to 10" via https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/parseInt – Mikael Korpela Jul 24 '16 at 19:24
  • 7
    KB = Kelvin bytes in SI units. which is nonsensical. It should be kB. – Brennan T Jul 10 '17 at 21:33
  • This fails --> Math.log(bytes) as it returns a negative value when the value of bytes is less than 1 (say 0.5) and – Devdutta Natu May 09 '19 at 15:37
  • How about adding `.toLocaleString()` so it gets convert to a user-friendly number. I'd also like to convert the return value into a template string, like this instead: return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm)).toLocaleString()} ${sizes[i]}` – dschu May 23 '19 at 08:54
  • 1
    It seems Apple uses 1000 instead of 1024. When testing a local file, the size reported by macOS is 472.3 MB. If `k = 1024` the size reported by the function is 450.45 MB. Changing it to `k = 1000` reports a size of 472.33 MB. – I0_ol Nov 19 '20 at 10:00
  • Why is this consistently incorrect? A size of 881,841 bytes prints out 861.17KB, A size of 2,651,236 bytes prints out 2.53 MB, and a size of 1,853,605 bytes prints out 1.77MB. These are just three examples, but it's consistently off. – Dan Zuzevich Jun 08 '21 at 16:39
  • ^ I am using the fixed es6 community version btw. – Dan Zuzevich Jun 08 '21 at 16:46
  • sometimes it displays 1000MB instead of 1GB – Gie Aug 06 '21 at 15:07
  • Until you surpass 1024MB it should continue to show the value in MB. One you pass 1024, then it should show 1 GB. – Daryl B Oct 12 '22 at 03:04
  • This formatBytes function seems to be inaccurate. I went to upload a 3.5mb file and it's converting it to 3.37 MB. Also, 1,000,000 bytes is being converted to 976.56 KB instead of 1mb. – Crystal Oct 19 '22 at 21:55
  • 1
    To be precise, if `k` is 1024 then the unit abbreviations should be `KiB`, `MiB`, `GiB`, etc. These are [kibibytes, mebibytes, gibibytes](https://physics.nist.gov/cuu/Units/binary.html), etc. – Phrogz Nov 17 '22 at 19:28
  • 2
    This isn't right, 1 kb is 1000 bytes, not 1024. So K should be 1000 – Ghiri Hari Dec 21 '22 at 12:10
  • Why 1024000 is showing 1000KB and not 1MB? – João Hamerski Apr 28 '23 at 13:20
  • Hello! i am using ANgular framework so this solution is to whomever end up here. I am getting data from an API and the size variable that I want is of type `string`, to make the function work i added `bytes = Number(bytes);` to the code and the type of bytes is `any` – jason May 04 '23 at 17:24
78

This solution includes a decimal point and a tenths-place digit if presenting less than ten of KB or greater units

const units = ['bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];
   
function niceBytes(x){

  let l = 0, n = parseInt(x, 10) || 0;

  while(n >= 1024 && ++l){
      n = n/1024;
  }
  
  return(n.toFixed(n < 10 && l > 0 ? 1 : 0) + ' ' + units[l]);
}

Results:

niceBytes(7)                   // 7 bytes
niceBytes(435)                 // 435 bytes
niceBytes(3398)                // 3.3 KiB
niceBytes(490398)              // 479 KiB
niceBytes(6544528)             // 6.2 MiB
niceBytes(23483023)            // 22 MiB
niceBytes(3984578493)          // 3.7 GiB
niceBytes(30498505889)         // 28 GiB
niceBytes(9485039485039445)    // 8.4 PiB

Note: Use the "Kib", etc. abbreviations when using base 1024, because "KB", etc. actually refers to base 1000. If you wish to calculate the value to base 1000, then just replace 1024 with 1000 in this function, and use the appropriate units (kB, MB, etc.)

Faust
  • 15,130
  • 9
  • 54
  • 111
  • 4
    *Thanks!* **Compressed:** `function niceBytes(a){let b=0,c=parseInt(a,10)||0;for(;1024<=c&&++b;)c/=1024;return c.toFixed(10>c&&0 – ashleedawg Nov 16 '20 at 10:50
  • as written elsewhere, 1MB=1000KB, not 1024. See https://en.wikipedia.org/wiki/Megabyte – Iacopo Feb 15 '23 at 07:05
  • @Iacopo: updated to address KiB, etc, rather than kB, as that seems to have been the OP's intent. – Faust Feb 18 '23 at 22:14
50
function formatBytes(bytes) {
    var marker = 1024; // Change to 1000 if required
    var decimal = 3; // Change as required
    var kiloBytes = marker; // One Kilobyte is 1024 bytes
    var megaBytes = marker * marker; // One MB is 1024 KB
    var gigaBytes = marker * marker * marker; // One GB is 1024 MB
    var teraBytes = marker * marker * marker * marker; // One TB is 1024 GB

    // return bytes if less than a KB
    if(bytes < kiloBytes) return bytes + " Bytes";
    // return KB if less than a MB
    else if(bytes < megaBytes) return(bytes / kiloBytes).toFixed(decimal) + " KB";
    // return MB if less than a GB
    else if(bytes < gigaBytes) return(bytes / megaBytes).toFixed(decimal) + " MB";
    // return GB if less than a TB
    else return(bytes / gigaBytes).toFixed(decimal) + " GB";
}
Jayram
  • 18,820
  • 6
  • 51
  • 68
35

Here's a one liner:

val => ['Bytes','Kb','Mb','Gb','Tb'][Math.floor(Math.log2(val)/10)]

Or even:

v => 'BKMGT'[~~(Math.log2(v)/10)]

With count:

function shortenBytes(n) {
    const k = n > 0 ? Math.floor((Math.log2(n)/10)) : 0;
    const rank = (k > 0 ? 'KMGT'[k - 1] : '') + 'b';
    const count = Math.floor(n / Math.pow(1024, k));
    return count + rank;
}
Alicia Sykes
  • 5,997
  • 7
  • 36
  • 64
iDaN5x
  • 616
  • 9
  • 12
  • 1
    Nice !, But if 1k is 1024 not 1000 ? – l2aelba Feb 23 '17 at 14:41
  • 2
    This calculation *is* treating 1k as 2^10, 1m as 2^20 and so on. if you want 1k to be 1000 you can change it a bit to use log10. – iDaN5x Feb 24 '17 at 20:24
  • 2
    Here's a version that treats 1K as 1000: `val => 'BKMGT'[~~(Math.log10(val)/3)]` – iDaN5x Feb 25 '17 at 12:08
  • 3
    This is nice! I expanded on this to return the full string I wanted from my function: `i = ~~(Math.log2(b)/10); return (b/Math.pow(1024,i)).toFixed(2) + ("KMGTPEZY"[i-1]||"") + "B"` – v0rtex Sep 06 '18 at 15:54
16

There are 2 real ways to represent sizes when related to bytes, they are SI units (10^3) or IEC units (2^10). There is also JEDEC but their method is ambiguous and confusing. I noticed the other examples have errors such as using KB instead of kB to represent a kilobyte so I decided to write a function that will solve each of these cases using the range of currently accepted units of measure.

There is a formatting bit at the end that will make the number look a bit better (at least to my eye) feel free to remove that formatting if it doesn't suit your purpose.

Enjoy.

// pBytes: the size in bytes to be converted.
// pUnits: 'si'|'iec' si units means the order of magnitude is 10^3, iec uses 2^10

function prettyNumber(pBytes, pUnits) {
    // Handle some special cases
    if(pBytes == 0) return '0 Bytes';
    if(pBytes == 1) return '1 Byte';
    if(pBytes == -1) return '-1 Byte';

    var bytes = Math.abs(pBytes)
    if(pUnits && pUnits.toLowerCase() && pUnits.toLowerCase() == 'si') {
        // SI units use the Metric representation based on 10^3 as a order of magnitude
        var orderOfMagnitude = Math.pow(10, 3);
        var abbreviations = ['Bytes', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
    } else {
        // IEC units use 2^10 as an order of magnitude
        var orderOfMagnitude = Math.pow(2, 10);
        var abbreviations = ['Bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];
    }
    var i = Math.floor(Math.log(bytes) / Math.log(orderOfMagnitude));
    var result = (bytes / Math.pow(orderOfMagnitude, i));

    // This will get the sign right
    if(pBytes < 0) {
        result *= -1;
    }

    // This bit here is purely for show. it drops the percision on numbers greater than 100 before the units.
    // it also always shows the full number of bytes if bytes is the unit.
    if(result >= 99.995 || i==0) {
        return result.toFixed(0) + ' ' + abbreviations[i];
    } else {
        return result.toFixed(2) + ' ' + abbreviations[i];
    }
}
Brennan T
  • 169
  • 1
  • 4
16

You can use the filesizejs library.

maurocchi
  • 640
  • 1
  • 6
  • 14
  • I guess this library gives the accurate representation, since 1024 bytes is 1 KB, not 1000 bytes (as provided by some other solutions here). Thanks @maurocchi – W.M. Aug 12 '16 at 15:04
  • 4
    @W.M. that statement is not true. 1kB = 1000 bytes. There are 1024 bytes in a Kibibyte. There has been confusion in the past so these two terms precisely explain the difference in size. – Brennan T Jul 10 '17 at 21:22
  • 2
    @BrennanT It depends how old you are. 1KB used to be 1024 bytes and most people over a certain age still see it as such. – kojow7 Nov 19 '17 at 21:46
  • 2
    for people who come here for a lib, here is better one: https://www.npmjs.com/package/pretty-bytes – ZuBB Oct 21 '21 at 09:18
8

Utility method to format bytes into the most logical magnitude (KB, MB, or GB)

Number.prototype.formatBytes = function() {
    var units = ['B', 'KB', 'MB', 'GB', 'TB'],
        bytes = this,
        i;
 
    for (i = 0; bytes >= 1024 && i < 4; i++) {
        bytes /= 1024;
    }
 
    return bytes.toFixed(2) + units[i];
}

let a = 235678; //bytes

console.log(a.formatBytes()); //result is 230.15KB
Dev Matee
  • 5,525
  • 2
  • 27
  • 33
8

Just slightly modified the code of @zayarTun answer to include an extra parameter representing the number of decimals in the result (also if the decimals are zero then no need to show a result like 15.00 KB, instead 15 KB is sufficient, that's why I wrapped the result value in parseFloat())

  bytesForHuman(bytes, decimals = 2) {
    let units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']

    let i = 0
    
    for (i; bytes > 1024; i++) {
        bytes /= 1024;
    }

    return parseFloat(bytes.toFixed(decimals)) + ' ' + units[i]
  }
medBouzid
  • 7,484
  • 10
  • 56
  • 86
6

Using bitwise operation would be a better solution. Try this

function formatSizeUnits(bytes)
{
    if ( ( bytes >> 30 ) & 0x3FF )
        bytes = ( bytes >>> 30 ) + '.' + ( bytes & (3*0x3FF )) + 'GB' ;
    else if ( ( bytes >> 20 ) & 0x3FF )
        bytes = ( bytes >>> 20 ) + '.' + ( bytes & (2*0x3FF ) ) + 'MB' ;
    else if ( ( bytes >> 10 ) & 0x3FF )
        bytes = ( bytes >>> 10 ) + '.' + ( bytes & (0x3FF ) ) + 'KB' ;
    else if ( ( bytes >> 1 ) & 0x3FF )
        bytes = ( bytes >>> 1 ) + 'Bytes' ;
    else
        bytes = bytes + 'Byte' ;
    return bytes ;
}
Buzz LIghtyear
  • 480
  • 5
  • 16
6

This works for me.

bytesForHuman(bytes) {
    let units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']

    let i = 0
    
    for (i; bytes > 1024; i++) {
        bytes /= 1024;
    }

    return bytes.toFixed(1) + ' ' + units[i]
}
Zayar Tun
  • 141
  • 2
  • 5
4

According to Aliceljm's answer, I removed 0 after decimal:

function formatBytes(bytes, decimals) {
    if(bytes== 0)
    {
        return "0 Byte";
    }
    var k = 1024; //Or 1 kilo = 1000
    var sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB"];
    var i = Math.floor(Math.log(bytes) / Math.log(k));
    return parseFloat((bytes / Math.pow(k, i)).toFixed(decimals)) + " " + sizes[i];
}
Community
  • 1
  • 1
abla
  • 334
  • 4
  • 7
4

function bytesToSize(bytes) {
  var sizes = ['B', 'K', 'M', 'G', 'T', 'P'];
  for (var i = 0; i < sizes.length; i++) {
    if (bytes <= 1024) {
      return bytes + ' ' + sizes[i];
    } else {
      bytes = parseFloat(bytes / 1024).toFixed(2)
    }
  }
  return bytes + ' P';
}

console.log(bytesToSize(234));
console.log(bytesToSize(2043));
console.log(bytesToSize(20433242));
console.log(bytesToSize(2043324243));
console.log(bytesToSize(2043324268233));
console.log(bytesToSize(2043324268233343));
Ruslan López
  • 4,433
  • 2
  • 26
  • 37
jasee
  • 49
  • 4
3

This solution builds upon previous solutions, but takes into account both metric and binary units:

function formatBytes(bytes, decimals, binaryUnits) {
    if(bytes == 0) {
        return '0 Bytes';
    }
    var unitMultiple = (binaryUnits) ? 1024 : 1000; 
    var unitNames = (unitMultiple === 1024) ? // 1000 bytes in 1 Kilobyte (KB) or 1024 bytes for the binary version (KiB)
        ['Bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']: 
        ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
    var unitChanges = Math.floor(Math.log(bytes) / Math.log(unitMultiple));
    return parseFloat((bytes / Math.pow(unitMultiple, unitChanges)).toFixed(decimals || 0)) + ' ' + unitNames[unitChanges];
}

Examples:

formatBytes(293489203947847, 1);    // 293.5 TB
formatBytes(1234, 0);   // 1 KB
formatBytes(4534634523453678343456, 2); // 4.53 ZB
formatBytes(4534634523453678343456, 2, true));  // 3.84 ZiB
formatBytes(4566744, 1);    // 4.6 MB
formatBytes(534, 0);    // 534 Bytes
formatBytes(273403407, 0);  // 273 MB
TxRegex
  • 2,347
  • 21
  • 20
2

I originally used @Aliceljm's answer for a file upload project I was working on, but recently ran into an issue where a file was 0.98kb but being read as 1.02mb. Here's the updated code I'm now using.

function formatBytes(bytes){
  var kb = 1024;
  var ndx = Math.floor( Math.log(bytes) / Math.log(kb) );
  var fileSizeTypes = ["bytes", "kb", "mb", "gb", "tb", "pb", "eb", "zb", "yb"];

  return {
    size: +(bytes / kb / kb).toFixed(2),
    type: fileSizeTypes[ndx]
  };
}

The above would then be called after a file was added like so

// In this case `file.size` equals `26060275` 
formatBytes(file.size);
// returns `{ size: 24.85, type: "mb" }`

Granted, Windows reads the file as being 24.8mb but I'm fine with the extra precision.

Community
  • 1
  • 1
theOneWhoKnocks
  • 600
  • 6
  • 13
2

Here is a solid Effective way to convert bytes . Only thing you need is to install mathjs library for accurate calculation . Just copy paste .

import { multiply, divide, round } from "mathjs";

class Size {
  constructor(value, unit) {
    this.value = value;
    this.unit = unit.toUpperCase();
  }
}

async function byteToSize(bytes) {
  const B = 1;
  const KB = multiply(B, 1024);
  const MB = multiply(KB, 1024);
  const GB = multiply(MB, 1024);
  const TB = multiply(GB, 1024);
  const PB = multiply(TB, 1024);

  if (bytes <= KB) {
    // @returns BYTE

    const result = round(divide(bytes, B));
    const unit = `B`;

    return new Size(result, unit);
  }

  if (bytes <= MB) {
    // @returns KILOBYTE

    const result = round(divide(bytes, KB));
    const unit = `KB`;

    return new Size(result, unit);
  }

  if (bytes <= GB) {
    // @returns MEGABYTE

    const result = round(divide(bytes, MB));
    const unit = `MB`;

    return new Size(result, unit);
  }

  if (bytes <= TB) {
    // @returns GIGABYTE

    const result = round(divide(bytes, GB));
    const unit = `GB`;

    return new Size(result, unit);
  }

  if (bytes <= PB) {
    // @returns TERABYTE

    const result = divide(bytes, TB).toFixed(2);
    const unit = `TB`;

    return new Size(result, unit);
  }

  if (bytes >= PB) {
    // @returns PETABYTE

    const result = divide(bytes, PB).toFixed(2);
    const unit = `PB`;

    return new Size(result, unit);
  }
}
2
const byteConversion = (bytes: number, decimals = 2) => {
if (bytes === 0) return '0 B';

const kiloByte = 1000;
const decimal = decimals < 0 ? 0 : decimals;
const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];

const i: number = Math.floor(Math.log(bytes) / Math.log(kiloByte));

return `${parseFloat((bytes / kiloByte ** i).toFixed(decimal))} ${sizes[i]}`;

};

ali tuna
  • 31
  • 3
2

This is not about converting bytes to other units, but it helps to correctly display the number and the unit for the current locale:

bytes.toLocaleString(undefined, {
  style: 'unit',
  unit: 'gigabyte',
})

More options and details can be found here: https://v8.dev/features/intl-numberformat#units

Holtwick
  • 1,849
  • 23
  • 29
1

I am updating @Aliceljm answer here. Since the decimal place matters for 1,2 digit numbers, I am round off the first decimal place and keep the first decimal place. For 3 digit number, I am round off the units place and ignoring the all decimal places.

getMultiplers : function(bytes){
    var unit = 1000 ;
    if (bytes < unit) return bytes ;
    var exp = Math.floor(Math.log(bytes) / Math.log(unit));
    var pre = "kMGTPE".charAt(exp-1);
    var result = bytes / Math.pow(unit, exp);
    if(result/100 < 1)
        return (Math.round( result * 10 ) / 10) +pre;
    else
        return Math.round(result) + pre;
}
omkar
  • 414
  • 4
  • 7
1

var SIZES = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];

function formatBytes(bytes, decimals) {
  for(var i = 0, r = bytes, b = 1024; r > b; i++) r /= b;
  return `${parseFloat(r.toFixed(decimals))} ${SIZES[i]}`;
}
1

I just wanted to share my input. I had this problem so my solution is this. This will convert lower units to higher units and vice versa just supply the argument toUnit and fromUnit

export function fileSizeConverter(size: number, fromUnit: string, toUnit: string ): number | string {
  const units: string[] = ['B', 'KB', 'MB', 'GB', 'TB'];
  const from = units.indexOf(fromUnit.toUpperCase());
  const to = units.indexOf(toUnit.toUpperCase());
  const BASE_SIZE = 1024;
  let result: number | string = 0;

  if (from < 0 || to < 0 ) { return result = 'Error: Incorrect units'; }

  result = from < to ? size / (BASE_SIZE ** to) : size * (BASE_SIZE ** from);

  return result.toFixed(2);
}

I got the idea from here

aRtoo
  • 1,686
  • 2
  • 18
  • 38
1

I use Recursive and assign level variable for proper Unit.

function getReadableByte(count, decimal=0, level=0) {
    let unitList = ["Bytes", "KB", "MB", "GB", "TB", "PT"];

    if (count >= 1024.0 && (level+1 < unitList.length)) {
        return getReadableByte(count/1024, decimal, ++level)
    }
    return `${decimal ? (count).toFixed(decimal) : Math.round(count)}${unitList[level]}`
}

console.log(getReadableByte(120, 2))
  • 2
    Would help to explanain your solution (think of beginners reading it). Especially the more elegant but intermediate-level constructs like (a) unit-symbols as array, (b) recursion, (c) template-string. – hc_dev Jul 01 '21 at 23:13
1

I made a algorithm 7 times faster (works like a ninja):

function rafaelFormatBytes(number){
  if(number == null || number === undefined || number <= 0) {
    return '0 Bytes';
  }
  var scaleCounter = 0;
  var scaleInitials = [' Bytes',' KB',' MB',' GB',' TB',' PB',' EB',' ZB',' YB'];
  while (number >= 1024 && scaleCounter < scaleInitials.length - 1){
    number /= 1024;
    scaleCounter++;
  }
  if(scaleCounter >= scaleInitials.length) scaleCounter = scaleInitials.length - 1;
  var compactNumber = number.toFixed(2)
                              .replace(/\.?0+$/,'')
                              .replace(/\B(?=(\d{3})+(?!\d))/g, ",");
  compactNumber += scaleInitials[scaleCounter];
  return compactNumber.trim();
}
var testNum = 0;

var startTime, endTime;

function start() {
  startTime = new Date();
};

function end() {
  endTime = new Date();
  var timeDiff = endTime - startTime; //in ms
  // strip the ms
  timeDiff /= 1000;

  // get seconds 
  var seconds = Math.round(timeDiff, 5);
  console.log(timeDiff + " seconds");
}

function formatBytes(a,b=2,k=1024){with(Math){let d=floor(log(a)/log(k));return 0==a?"0 Bytes":parseFloat((a/pow(k,d)).toFixed(max(0,b)))+" "+["Bytes","KB","MB","GB","TB","PB","EB","ZB","YB"][d]}}

console.log(formatBytes(1000000000000000000000000000));
console.log(rafaelFormatBytes(1000000000000000000000000000));

start();
for(i=0; i<100000; i++){
    formatBytes(1000000000000000);
}
end();
start();
for(i=0; i<100000; i++){
    rafaelFormatBytes(1000000000000000);
}
end();

... and the output:

827.18 YB
827.18 YB
0.293 seconds
0.039 seconds

Jesus Christ!!!!

Rafael Setragni
  • 160
  • 1
  • 6
1

You can use pretty-bytes library.

Install

npm install pretty-bytes

Usage

import prettyBytes from 'pretty-bytes';

prettyBytes(1337);
//=> '1.34 kB'

prettyBytes(100);
//=> '100 B'

// Display with units of bits
prettyBytes(1337, {bits: true});
//=> '1.34 kbit'

// Display file size differences
prettyBytes(42, {signed: true});
//=> '+42 B'

// Localized output using German locale
prettyBytes(1337, {locale: 'de'});
//=> '1,34 kB'
Ilyich
  • 4,966
  • 3
  • 39
  • 27
1

more flexible and considered max pow in sizes list (upgraded l2aelba answer)

function formatBytes(bytes, decimals = 2, isBinary = false) {
      const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']; // or ['B', 'KB', 'MB', 'GB', 'TB']
    
      if (!+bytes) {
        return `0 ${sizes[0]}`;
      }
    
      const inByte = isBinary ? 1024 : 1000;
      const dm = decimals < 0 ? 0 : decimals;
    
      const pow = Math.floor(Math.log(bytes) / Math.log(inByte));
      const maxPow = Math.min(pow, sizes.length - 1);
    
      return `${parseFloat((bytes / Math.pow(inByte, maxPow)).toFixed(dm))} ${
        sizes[maxPow]
      }`;
    }
Ilmur
  • 11
  • 1
0

This is how a byte should be shown to a human:

function bytesToHuman(bytes, decimals = 2) {
  // https://en.wikipedia.org/wiki/Orders_of_magnitude_(data)
  const units = ["bytes", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"]; // etc

  let i = 0;
  let h = 0;

  let c = 1 / 1023; // change it to 1024 and see the diff

  for (; h < c && i < units.length; i++) {
    if ((h = Math.pow(1024, i) / bytes) >= c) {
      break;
    }
  }

  // remove toFixed and let `locale` controls formatting
  return (1 / h).toFixed(decimals).toLocaleString() + " " + units[i];
}

// test
for (let i = 0; i < 9; i++) {
  let val = i * Math.pow(10, i);
  console.log(val.toLocaleString() + " bytes is the same as " + bytesToHuman(val));

}

// let's fool around
console.log(bytesToHuman(1023));
console.log(bytesToHuman(1024));
console.log(bytesToHuman(1025));
Eugen Mihailescu
  • 3,553
  • 2
  • 32
  • 29
0
function bytes2Size(byteVal){
    var units=["Bytes", "KB", "MB", "GB", "TB"];
    var kounter=0;
    var kb= 1024;
    var div=byteVal/1;
    while(div>=kb){
        kounter++;
        div= div/kb;
    }
    return div.toFixed(1) + " " + units[kounter];
}
Kjut
  • 56
  • 4
  • This function is easy-to-understand and follow - you can implement it in any language. It's a repeated division of the byte value until you attain the byte level (unit) that is greater than 1kb – Kjut Apr 11 '20 at 03:27
  • Just a quick note, There are differences between binary prefixes. Some follow SI base 10 rule and some follow base 2. You can read more [here](https://cseducators.stackexchange.com/a/4446). However, if you consider k to be 1024, instead of dividsion, you can simply use [shift operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Right_shift) like `byteVal >> 10` . Also [you would better use `Math.trunc()` to cast real numbers to integers](https://stackoverflow.com/a/596503/3994502) instead ofdivision by 1. – Tala Apr 11 '20 at 05:59
  • Please don't post only code as answer, but also provide an explanation what your code does and how it solves the problem of the question. Answers with an explanation are usually of higher quality, and are more likely to attract upvotes. – Mark Rotteveel Apr 11 '20 at 07:09
0

ONE-LINER

const b2s=t=>{let e=Math.log2(t)/10|0;return(t/1024**(e=e<=0?0:e)).toFixed(3)+"BKMGP"[e]};

console.log(b2s(0));
console.log(b2s(123));
console.log(b2s(123123));
console.log(b2s(123123123));
console.log(b2s(123123123123));
console.log(b2s(123123123123123));
nkitku
  • 4,779
  • 1
  • 31
  • 27
0

Same answer from @Aliceljm , but in a "more didactic" way. Thanks! =D

function formatBytes(numBytes, decPlaces) {
    /* Adjust the number of bytes informed for the most appropriate metric according
    to its value.

    Args:
        numBytes (number): The number of bytes (integer);
        decPlaces (Optional[number])): The number of decimal places (integer). If
            it is "undefined" the value "2" will be adopted.

    Returns:
        string: The number adjusted together with the most appropriate metric. */

    if (numBytes === 0) {
        return "0 Bytes";
    }

    // NOTE: 1 KB is equal to 1024 Bytes. By Questor
    // [Ref(s).: https://en.wikipedia.org/wiki/Kilobyte ]
    var oneKByte = 1024;

    // NOTE: Treats if the "decPlaces" is "undefined". If it is "undefined" the value
    // "2" will be adopted. By Questor
    if (decPlaces === undefined || decPlaces === "") {
        decPlaces = 2;
    }

    var byteMtrcs = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
    // Byte Metrics

    // NOTE: Defines the factor for the number of bytes and the metric. By Questor
    var mtrcNumbFactor = Math.floor(Math.log(numBytes) / Math.log(oneKByte));
    // Metrics Number Factor

    return parseFloat((numBytes / Math.pow(oneKByte, mtrcNumbFactor)).
            toFixed(decPlaces)) + " " + byteMtrcs[mtrcNumbFactor];
}
Eduardo Lucio
  • 1,771
  • 2
  • 25
  • 43
0

I had a problem of meta data on files returning from the server with different size units. I used @Alicejim response and tried to do it more general. sharing the code here, maybe it will help someone.

enum SizeUnits {
   Bytes = 'Bytes',
   KB = 'KB',
   MB = 'MB',
   GB = 'GB',
   TB = 'TB',
   PB = 'PB',
   EB = 'EB',
   ZB = 'ZB',
   YB = 'YB'
}
function convertSizeUnites(size: number, sourceSizeUnits: SizeUnits, targetSizeUnits: SizeUnits) {
    const i = Object.keys(SizeUnits).indexOf(sourceSizeUnits);
    const sizeInBytes = size * Math.pow(1024, i);
    const j = Object.keys(SizeUnits).indexOf(targetSizeUnits);
    return sizeInBytes / Math.pow(1024, j);
}
function formatSize(size: number, measureUnit: SizeUnits, decimals = 2) {
    if (size === 0) return '0 Bytes';
    const sizeInBytes = convertSizeUnites(size, measureUnit, SizeUnits.Bytes);
    const dm = decimals < 0 ? 0 : decimals;
    const i = Math.floor(Math.log(sizeInBytes) / Math.log(1024));
    return parseFloat((sizeInBytes / Math.pow(1024, i)).toFixed(dm)) + ' ' + 
    Object.keys(SizeUnits)[i];
}
tomer
  • 19
  • 1
  • 3
0

This is a follow-up to the currently highest-ranked answer.

Edge case

I found an edge case: very tiny amounts of bytes! Specifically, when the number of bytes is between -1 and 1 (exclusive).

For example, consider 0.25 bytes. In this case, Math.floor(Math.log(0.25) / Math.log(1024)) will return -1. Since -1 is not a valid index, formatBytes(0.25) will return something like "0.25 undefined".

Here is an illustration of the edge case using Wolfram Alpha.

Fix

I fixed this by adding Math.max(0, ...):

Math.max(0, Math.floor(Math.log(bytes) / Math.log(1024))

Math.max(0, ...) ensures that the index value will always be at least 0.

cnd
  • 1
  • 1
0

This worked for me with react, typescript.

export const FormatBytes = (bytes: number) => {
  const units = ['b', 'kb', 'mb', 'gb', 'tb'];

  let i = 0;

  for (i; bytes >= 1024 && i < 4; i++) {
    bytes /= 1024;
  }

  return `${bytes.toFixed(2)} ${units[i]}`;
};

Evaldas
  • 169
  • 7
0
function bytes(value = 1, from = "mb", to = "b") {
    const bytes = {'b':1,'kb':2,'mb':3,'gb':4,'tb':5,'pb':6,'eb':7,'zb':8,'yb':9};
    let a = bytes[from], b = bytes[to];
    if(a>b)
        for(let i = 0;i < (a-b);i++)
            value *=1024;
    else
        for(let i = 0;i < (b-a);i++)
            value /=1024;
    return value;
}
console.log(bytes());
console.log(bytes(1024, "kb", "mb"));
console.log(bytes(1, "gb", "kb"));
  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jun 01 '23 at 02:53
-1

THIS IS THE EASIEST SOLUTION.

STEP 1:

npm install bytes

Weekly Downloads: 54,425,499

STEP 2:

const bytes = require('bytes'); // you can use import as well

STEP 3:

  function formatBytes(bytes) {
     return bytes(bytes, { unitSeparator: ' ' });
   }

RESULT

console.log(formatBytes(123456789)); // "117.74 MB"
-9

Try this simple workaround.

var files = $("#file").get(0).files;               
                var size = files[0].size;
                if (size >= 5000000) {
alert("File size is greater than or equal to 5 MB");
}
Liladhar
  • 383
  • 5
  • 20