Javascript 将文件大小(以字节为单位)转换为人类可读的字符串

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10420352/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 01:14:07  来源:igfitidea点击:

Converting file size in bytes to human-readable string

javascriptfilesizehuman-readable

提问by Hristo

I'm using this function to convert a file size in bytes to a human-readable file size:

我正在使用此函数将文件大小(以字节为单位)转换为人类可读的文件大小:

function getReadableFileSizeString(fileSizeInBytes) {
    var i = -1;
    var byteUnits = [' kB', ' MB', ' GB', ' TB', 'PB', 'EB', 'ZB', 'YB'];
    do {
        fileSizeInBytes = fileSizeInBytes / 1024;
        i++;
    } while (fileSizeInBytes > 1024);

    return Math.max(fileSizeInBytes, 0.1).toFixed(1) + byteUnits[i];
};

However, it seems like this isn't 100% accurate. For example:

但是,这似乎不是 100% 准确。例如:

getReadableFileSizeString(1551859712); // output is "1.4 GB"

Shouldn't this be "1.5 GB"? It seems like the division by 1024 is losing precision. Am I totally misunderstanding something or is there a better way to do this?

这不应该"1.5 GB"吗?似乎除以 1024 正在失去精度。我是完全误解了什么还是有更好的方法来做到这一点?

采纳答案by Neil

It depends on whether you want to use the binary or decimal convention.

这取决于您要使用二进制还是十进制约定。

RAM, for instance, is always measured in binary, so to express 1551859712 as ~1.4GiB would be correct.

例如,RAM 总是以二进制表示,因此将 1551859712 表示为 ~1.4GiB 是正确的。

On the other hand, hard disk manufacturers like to use decimal, so they would call it ~1.6GB.

另一方面,硬盘制造商喜欢使用十进制,因此他们将其称为~1.6GB。

And just to be confusing, floppy disks use a mixture of the two systems - their 1MB is actually 1024000 bytes.

令人困惑的是,软盘混合使用了这两种系统——它们的 1MB 实际上是 1024000 字节。

回答by mpen

Here's one I wrote:

这是我写的一篇:

function humanFileSize(bytes, si=false, dp=1) {
  const thresh = si ? 1000 : 1024;

  if (Math.abs(bytes) < thresh) {
    return bytes + ' B';
  }

  const units = si 
    ? ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] 
    : ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];
  let u = -1;
  const r = 10**dp;

  do {
    bytes /= thresh;
    ++u;
  } while (Math.round(Math.abs(bytes) * r) / r >= thresh && u < units.length - 1);


  return bytes.toFixed(dp) + ' ' + units[u];
}


console.log(humanFileSize(5000, true))  // 5.0 kB
console.log(humanFileSize(5000, false))  // 4.9 KiB
console.log(humanFileSize(-10000000000000000000000000000))  // -8271.8 YiB
console.log(humanFileSize(999949, true))  // 999.9 kB
console.log(humanFileSize(999950, true))  // 1.0 MB
console.log(humanFileSize(999950, true, 2))  // 999.95 kB
console.log(humanFileSize(999500, true, 0))  // 1 MB

回答by Andrew V.

Another embodiment of the calculation

计算的另一个实施例

function humanFileSize(size) {
    var i = Math.floor( Math.log(size) / Math.log(1024) );
    return ( size / Math.pow(1024, i) ).toFixed(2) * 1 + ' ' + ['B', 'kB', 'MB', 'GB', 'TB'][i];
};

回答by cocco

Here is a prototype to convert a number to a readable string respecting the new international standards.

这是一个将数字转换为符合新国际标准的可读字符串的原型。

There are two ways to represent big numbers: You could either display them in multiples of 1000 = 10 3 (base 10) or 1024 = 2 10 (base 2). If you divide by 1000, you probably use the SI prefix names, if you divide by 1024, you probably use the IEC prefix names. The problem starts with dividing by 1024. Many applications use the SI prefix names for it and some use the IEC prefix names. The current situation is a mess. If you see SI prefix names you do not know whether the number is divided by 1000 or 1024

有两种表示大数字的方法:您可以以 1000 = 10 3(基数 10)或 1024 = 2 10(基数 2)的倍数显示它们。如果除以 1000,则可能使用 SI 前缀名称,如果除以 1024,则可能使用 IEC 前缀名称。问题从除以 1024 开始。许多应用程序使用 SI 前缀名称,有些应用程序使用 IEC 前缀名称。目前的情况是一团糟。如果您看到 SI 前缀名称,您不知道该数字是除以 1000 还是 1024

https://wiki.ubuntu.com/UnitsPolicy

https://wiki.ubuntu.com/UnitsPolicy

http://en.wikipedia.org/wiki/Template:Quantities_of_bytes

http://en.wikipedia.org/wiki/Template:Quantities_of_bytes

Object.defineProperty(Number.prototype,'fileSize',{value:function(a,b,c,d){
 return (a=a?[1e3,'k','B']:[1024,'K','iB'],b=Math,c=b.log,
 d=c(this)/c(a[0])|0,this/b.pow(a[0],d)).toFixed(2)
 +' '+(d?(a[1]+'MGTPEZY')[--d]+a[2]:'Bytes');
},writable:false,enumerable:false});

This function contains no loop, and so it's probably faster than some other functions.

此函数包含 no loop,因此它可能比其他一些函数更快。

Usage:

用法:

IEC prefix

IEC前缀

console.log((186457865).fileSize()); // default IEC (power 1024)
//177.82 MiB
//KiB,MiB,GiB,TiB,PiB,EiB,ZiB,YiB

SI prefix

SI前缀

console.log((186457865).fileSize(1)); //1,true for SI (power 1000)
//186.46 MB 
//kB,MB,GB,TB,PB,EB,ZB,YB

i set the IEC as default because i always used binary mode to calculate the size of a file... using the power of 1024

我将 IEC 设置为默认值,因为我总是使用二进制模式来计算文件的大小...使用 1024 的幂



If you just want one of them in a short oneliner function:

如果您只想在简短的 oneliner 函数中使用其中之一:

SI

SI

function fileSizeSI(a,b,c,d,e){
 return (b=Math,c=b.log,d=1e3,e=c(a)/c(d)|0,a/b.pow(d,e)).toFixed(2)
 +' '+(e?'kMGTPEZY'[--e]+'B':'Bytes')
}
//kB,MB,GB,TB,PB,EB,ZB,YB

IEC

国际电工委员会

function fileSizeIEC(a,b,c,d,e){
 return (b=Math,c=b.log,d=1024,e=c(a)/c(d)|0,a/b.pow(d,e)).toFixed(2)
 +' '+(e?'KMGTPEZY'[--e]+'iB':'Bytes')
}
//KiB,MiB,GiB,TiB,PiB,EiB,ZiB,YiB

Usage:

用法:

console.log(fileSizeIEC(7412834521));

if you have some questions about the functions just ask

如果您对功能有一些疑问,请询问

回答by Joshaven Potter

sizeOf = function (bytes) {
  if (bytes == 0) { return "0.00 B"; }
  var e = Math.floor(Math.log(bytes) / Math.log(1024));
  return (bytes/Math.pow(1024, e)).toFixed(2)+' '+' KMGTP'.charAt(e)+'B';
}

sizeOf(2054110009);
//=> "1.91 GB"

sizeOf(7054110);
//=> "6.73 MB"

sizeOf( (3*1024*1024) );
//=> "3.00 MB"

大小(2054110009);
//=> "1.91 GB"

大小(7054110);
//=> "6.73 MB"

sizeOf((3*1024*1024));
//=> "3.00 MB"

回答by Patrick Mencias-lewis

Solution as ReactJS Component

作为 ReactJS 组件的解决方案

Bytes = React.createClass({
    formatBytes() {
        var i = Math.floor(Math.log(this.props.bytes) / Math.log(1024));
        return !this.props.bytes && '0 Bytes' || (this.props.bytes / Math.pow(1024, i)).toFixed(2) + " " + ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'][i]
    },
    render () {
        return (
            <span>{ this.formatBytes() }</span>
        );
    }
});

UPDATEFor those using es6 here is a stateless version of this same component

更新对于那些使用 es6 的人,这里是同一个组件的无状态版本

const sufixes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
const getBytes = (bytes) => {
  const i = Math.floor(Math.log(bytes) / Math.log(1024));
  return !bytes && '0 Bytes' || (bytes / Math.pow(1024, i)).toFixed(2) + " " + sufixes[i];
};

const Bytes = ({ bytes }) => (<span>{ getBytes(bytes) }</span>);

Bytes.propTypes = {
  bytes: React.PropTypes.number,
};

回答by KitKat

Based on cocco's idea, here's a less compact -but hopefully more comprehensive- example.

基于cocco的想法,这里有一个不太紧凑但希望更全面的示例。

<!DOCTYPE html>
<html>
<head>
<title>File info</title>

<script>
<!--
function fileSize(bytes) {
    var exp = Math.log(bytes) / Math.log(1024) | 0;
    var result = (bytes / Math.pow(1024, exp)).toFixed(2);

    return result + ' ' + (exp == 0 ? 'bytes': 'KMGTPEZY'[exp - 1] + 'B');
}

function info(input) {
    input.nextElementSibling.textContent = fileSize(input.files[0].size);
} 
-->
</script>
</head>

<body>
<label for="upload-file"> File: </label>
<input id="upload-file" type="file" onchange="info(this)">
<div></div>
</body>
</html> 

回答by Nick Kuznia

Another example similar to those here

另一个类似于此处的示例

function fileSize(b) {
    var u = 0, s=1024;
    while (b >= s || -b >= s) {
        b /= s;
        u++;
    }
    return (u ? b.toFixed(1) + ' ' : b) + ' KMGTPEZY'[u] + 'B';
}

It measures negligibly better performance than the others with similar features.

它测量的性能比具有类似特征的其他性能好得可以忽略不计。

回答by Camilo Martin

I wanted the "file manager" behavior (e.g., Windows Explorer) where the number of decimal places is proportional to the number size. Seemingly none of the other answers does this.

我想要“文件管理器”行为(例如,Windows 资源管理器),其中小数位数与数字大小成正比。似乎其他答案都没有做到这一点。

function humanFileSize(size) {
    if (size < 1024) return size + ' B'
    let i = Math.floor(Math.log(size) / Math.log(1024))
    let num = (size / Math.pow(1024, i))
    let round = Math.round(num)
    num = round < 10 ? num.toFixed(2) : round < 100 ? num.toFixed(1) : round
    return `${num} ${'KMGTPEZY'[i-1]}B`
}

Here's some examples:

下面是一些例子:

humanFileSize(0)          // "0 B"
humanFileSize(1023)       // "1023 B"
humanFileSize(1024)       // "1.00 KB"
humanFileSize(10240)      // "10.0 KB"
humanFileSize(102400)     // "100 KB"
humanFileSize(1024000)    // "1000 KB"
humanFileSize(12345678)   // "11.8 MB"
humanFileSize(1234567890) // "1.15 GB"

回答by Ebrahim Byagowi

Based on cocco's answerbut slightly desugerified (honestly, ones I was comfortable with are remained/added) and doesn't show trailing zeros but still supports 0, hope to be useful for others:

基于cocco 的回答但稍微去糖化了(老实说,我很满意的那些被保留/添加)并且不显示尾随零但仍然支持 0,希望对其他人有用:

function fileSizeSI(size) {
    var e = (Math.log(size) / Math.log(1e3)) | 0;
    return +(size / Math.pow(1e3, e)).toFixed(2) + ' ' + ('kMGTPEZY'[e - 1] || '') + 'B';
}


// test:
document.write([0, 23, 4322, 324232132, 22e9, 64.22e12, 76.22e15, 64.66e18, 77.11e21, 22e24].map(fileSizeSI).join('<br>'));