正确的方法转换大小字节到KB, MB, GB在JavaScript

我得到这段代码隐蔽大小字节通过PHP。

现在我想使用JavaScript将这些大小转换为人类可读的大小。我尝试将这段代码转换为JavaScript,看起来像这样:

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

这是正确的做法吗?有没有更简单的方法?

469606 次浏览

使用位操作将是一个更好的解决方案。试试这个

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

从这个:()


未缩小和ES6'ed:(由社区)

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


const k = 1024
const dm = decimals < 0 ? 0 : decimals
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']


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

简化版 (由StackOverflow的社区,缩小了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","KB","MB","GB","TB","PB","EB","ZB","YB"][d]}`}

用法:

// formatBytes(bytes, decimals)


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

PS:根据需要更改k = 1000sizes = ["..."] (bitsbytes)

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";
}

当与字节相关时,有两种真实的方法来表示大小,它们是SI单位(10^3)或IEC单位(2^10)。也有JEDEC,但他们的方法是模糊的和令人困惑的。我注意到其他示例有错误,例如使用KB而不是KB来表示千字节,因此我决定编写一个函数,使用当前接受的度量单位的范围来解决这些情况。

在结尾有一个格式化的地方,这将使数字看起来更好一点(至少在我看来),如果它不适合你的目的,请随意删除这个格式。

享受。

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

你可以使用filesizejs库。

根据Aliceljm的答案,我在小数点后去掉了0:

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

试试这个简单的解决方法。

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");
}

我最初使用@Aliceljm的答案,我正在进行的一个文件上传项目,但最近遇到了一个问题,其中一个文件是0.98kb,但读取为1.02mb。下面是我现在使用的更新代码。

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

在像这样添加文件之后,上面的函数将被调用

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

当然,Windows读取文件为24.8mb,但我对额外的精度很好。

我正在更新@ al冰岛的答案。由于小数点对于1,2位数的数字很重要,所以我舍入了第一个小数点并保留第一个小数点。对于3位数的数字,我舍入个位数,忽略所有小数点后的位置。

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

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

这个解决方案建立在以前的解决方案的基础上,但同时考虑了公制和二进制单位:

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

例子:

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

如果表示的单位小于10 KB或更大,则此解决方案包括一个小数点和一个十分位数字

const units = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
   

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

结果:

niceBytes(435)                 // 435 bytes
niceBytes(3398)                // 3.3 KB
niceBytes(490398)              // 479 KB
niceBytes(6544528)             // 6.2 MB
niceBytes(23483023)            // 22 MB
niceBytes(3984578493)          // 3.7 GB
niceBytes(30498505889)         // 28 GB
niceBytes(9485039485039445)    // 8.4 PB

这里有一句话:

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

甚至:

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

与数:

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

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

这是一个字节应该如何显示给人类:

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

我只是想分享我的想法。我遇到了这个问题,所以我的解决方案是这样的。这将把较低的单位转换为较高的单位,反之亦然,只需提供参数toUnitfromUnit

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);
}

我从在这里得到这个想法

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

一行程序

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

@ alicejm也给出了同样的答案,但“更有说教意味”。道路谢谢!= 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];
}

我使用递归和分配水平变量为适当的单位。

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

这对我很有用。

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

这是一个坚实的有效的方法来转换字节。你唯一需要做的就是安装mathjs库来进行精确的计算。复制粘贴即可。

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);
}
}

我让算法快了7倍(就像忍者一样):

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();

... 输出:

827.18 YB
827.18 YB
0.293 seconds
0.039 seconds

耶稣基督!

将字节格式化为最符合逻辑大小(KB、MB或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

我有一个问题的元数据从服务器返回不同大小的单位。我使用了@Alicejim response,并试图让它更通用。在这里分享代码,也许会帮助到一些人。

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

只是稍微修改了@zayarTun答案的代码,以包括一个额外的参数,表示结果中的小数数(如果小数为零,则不需要显示像15.00 KB这样的结果,而是15 KB就足够了,这就是为什么我将结果值包装在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]
}
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]}`;

};

这是当前排名最高的回答的后续。

边界情况

我发现了一个边缘情况:非常小的字节数!具体来说,当字节数在-1和1之间(独占)时。

例如,考虑0.25字节。在这种情况下,Math.floor(Math.log(0.25) / Math.log(1024))将返回-1。由于-1不是一个有效的索引,formatBytes(0.25)将返回类似“0.25 undefined"”的值。

下面是使用Wolfram Alpha的边缘情况的插图

修复

我通过添加Math.max(0, ...)来修复这个问题:

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

Math.max(0, ...)确保索引值始终至少为0。

你可以使用pretty-bytes库。

安装

npm install pretty-bytes

使用

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'

更灵活,考虑最大pow尺寸列表 (升级的l2aelba answer)

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

这不是关于将字节转换为其他单位,但它有助于正确显示当前地区的数字和单位:

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

更多选项和细节可以在这里找到:https://v8.dev/features/intl-numberformat#units