Correct way to convert size in bytes to KB, MB, GB

2019-01-03 03:41发布

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?

14条回答
趁早两清
2楼-- · 2019-01-03 04:20

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];
    }
}
查看更多
闹够了就滚
3楼-- · 2019-01-03 04:20

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];
}
查看更多
Summer. ? 凉城
4楼-- · 2019-01-03 04:22

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.

查看更多
看我几分像从前
5楼-- · 2019-01-03 04:22

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;
}
查看更多
我命由我不由天
6楼-- · 2019-01-03 04:22

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]}`;
}

查看更多
萌系小妹纸
7楼-- · 2019-01-03 04:27

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");
}
查看更多
登录 后发表回答