Forma correcta de convertir el tamaño en bytes a KB, MB, GB en JavaScript


258

Obtuve este código para convertir el tamaño en bytes a través de PHP.

Ahora quiero convertir esos tamaños a tamaños legibles por humanos usando JavaScript. Traté de convertir este código a JavaScript, que se ve así:

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

¿Es esta la forma correcta de hacer esto? hay una manera mas facil?


55
Esto realmente se convierte en GiB, MiB y KiB. Esto es estándar para los tamaños de archivo, pero no siempre para los tamaños de dispositivo.
David Schwartz

Respuestas:


761

De esto: ( fuente )

function bytesToSize(bytes) {
   var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
   if (bytes == 0) return '0 Byte';
   var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
   return Math.round(bytes / Math.pow(1024, i), 2) + ' ' + sizes[i];
}

Nota: Este es el código original. Utilice la versión fija a continuación. Aliceljm ya no activa su código copiado


Ahora, versión fija no minificada, y ES6'ed: (por comunidad)

function formatBytes(bytes, decimals = 2) {
    if (bytes === 0) 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];
}

Ahora, Versión fija: (por la comunidad de Stackoverflow, + Minificado por JSCompress )

function formatBytes(a,b=2){if(0===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]}

Uso:

// formatBytes(bytes,decimals)

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

Demo / fuente:

function formatBytes(bytes, decimals = 2) {
    if (bytes === 0) 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 **
var p = document.querySelector('p'),
    input = document.querySelector('input');
    
function setText(v){
    p.innerHTML = formatBytes(v);
}
// bind 'input' event
input.addEventListener('input', function(){ 
    setText( this.value )
})
// set initial text
setText(input.value);
<input type="text" value="1000">
<p></p>

PD: Cambia k = 1000o sizes = ["..."]como quieras ( bits o bytes )


8
(1) ¿por qué bytes = 0 es "n / a"? ¿No es solo "0 B"? (2) Math.round no tiene parámetro de precisión. Mejor uso(bytes / Math.pow(1024, i)).toPrecision(3)
desfavorecido

44
toFixed(n)es probablemente más apropiado que toPrecision(n)tener una precisión constante para todos los valores. Y para evitar ceros finales (ej . bytesToSize(1000) // return "1.00 KB":) podríamos usar parseFloat(x). Sugiero sustituir la última línea por: return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];. Con el cambio anterior, los resultados son: 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

3
Creo que la forma plural se usa para 0: '0 Bytes'
nima

14
Diría que minify es bueno, pero en una respuesta de stackexchange es mejor tener un código más detallado y legible.
donquixote 01 de

2
KB = Kelvin bytes en unidades SI. lo cual no tiene sentido. Debería ser kB.
Brennan T

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

34
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;
  }
  //include a decimal point and a tenths-place digit if presenting 
  //less than ten of KB or greater units
  return(n.toFixed(n < 10 && l > 0 ? 1 : 0) + ' ' + units[l]);
}

Resultados:

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

15

Puede usar la biblioteca filesizejs .


Supongo que esta biblioteca ofrece una representación precisa, ya que 1024 bytes son 1 KB, no 1000 bytes (como lo proporcionan algunas otras soluciones aquí). Gracias @maurocchi
WM

3
@WM esa afirmación no es cierta. 1kB = 1000 bytes. Hay 1024 bytes en un Kibibyte. Ha habido confusión en el pasado, por lo que estos dos términos explican con precisión la diferencia de tamaño.
Brennan T

2
@BrennanT Depende de la edad que tengas. 1 KB solía ser 1024 bytes y la mayoría de las personas mayores de cierta edad todavía lo ven como tal.
kojow7

14

Hay 2 formas reales de representar tamaños cuando se relacionan con bytes, son unidades SI (10 ^ 3) o unidades IEC (2 ^ 10). También existe JEDEC, pero su método es ambiguo y confuso. Noté que los otros ejemplos tienen errores como el uso de KB en lugar de kB para representar un kilobyte, así que decidí escribir una función que resolverá cada uno de estos casos usando el rango de unidades de medida actualmente aceptadas.

Hay un bit de formato al final que hará que el número se vea un poco mejor (al menos a mi parecer), siéntase libre de eliminar ese formato si no se ajusta a su propósito.

Disfrutar.

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

13

Aquí hay un trazador de líneas:

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

O incluso:

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


¡Bien !, pero si 1k es 1024 no 1000?
l2aelba

2
Este cálculo está tratando 1k como 2 ^ 10, 1m como 2 ^ 20 y así sucesivamente. si quieres que 1k sea 1000, puedes cambiarlo un poco para usar log10.
iDaN5x

1
Aquí hay una versión que trata 1K como 1000:val => 'BKMGT'[~~(Math.log10(val)/3)]
iDaN5x

1
¡Esto es bonito! i = ~~(Math.log2(b)/10); return (b/Math.pow(1024,i)).toFixed(2) + ("KMGTPEZY"[i-1]||"") + "B"
Expandí

4

Usar una operación bit a bit sería una mejor solución. Prueba esto

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

1
Obtenga los bytes restantes. Eso proporcionará la porción decimal.
Buzz LIghtyear

1
Es 1024. Si necesita 100, cambie los bits en consecuencia.
Buzz LIghtyear


3
No tome el código de Internet sin entenderlo o al menos probarlo. Este es un buen ejemplo de código que simplemente está mal. Intenta ejecutarlo pasando 3 (devuelve "1 Bytes") o 400000.
Amir Haghighat

10
Estimado Amir Haghighat, este es un código básico escrito exclusivamente por mí. En javasript post 32 bits de valor entero, el código no funcionará ya que el entero es de solo cuatro bytes. Estas son informaciones básicas de programación que debes conocer. Stackoverflow es solo para guiar a las personas y no para alimentar con cuchara.
Buzz LIghtyear

4

De acuerdo con Aliceljm la respuesta de , 0 después del 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];
}

2

Originalmente utilicé la respuesta de @Aliceljm para un proyecto de carga de archivos en el que estaba trabajando, pero recientemente encontré un problema en el que un archivo estaba 0.98kbsiendo leído como 1.02mb. Aquí está el código actualizado que estoy usando ahora.

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

Lo anterior se llamaría después de agregar un archivo así

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

Por supuesto, Windows lee el archivo como tal, 24.8mbpero estoy bien con la precisión adicional.


2

Esta solución se basa en soluciones anteriores, pero tiene en cuenta las unidades métricas y binarias:

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

Ejemplos:

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

2

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


2

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

Estoy actualizando la respuesta de @Aliceljm aquí. Como el lugar decimal es importante para los números de 1,2 dígitos, redondeo el primer lugar decimal y mantengo el primer lugar decimal. Para el número de 3 dígitos, redondeo el lugar de las unidades e ignoro todos los lugares decimales.

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

0

Así es como se debe mostrar un byte a un humano:

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

0

Solo quería compartir mi opinión. Tuve este problema, así que mi solución es esta. Esto convertirá unidades más bajas en unidades más altas y viceversa, solo proporcione el argumento toUnityfromUnit

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

Tengo la idea de aqui


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

Esta función es fácil de entender y seguir: puede implementarla en cualquier idioma. Es una división repetida del valor del byte hasta que alcanza el nivel de byte (unidad) que es mayor que 1
kb

Solo una nota rápida, hay diferencias entre los prefijos binarios. Algunos siguen la regla SI base 10 y algunos siguen la base 2. Puede leer más aquí . Sin embargo, si considera que k es 1024, en lugar de división, simplemente puede usar el operador shift como byteVal >> 10. También sería mejor usar Math.trunc()para emitir números reales a enteros en lugar de la división por 1.
Astucia

No publique solo el código como respuesta, sino que también proporcione una explicación de lo que hace su código y cómo resuelve el problema de la pregunta. Las respuestas con una explicación son generalmente de mayor calidad y es más probable que atraigan votos positivos.
Mark Rotteveel

-7

Prueba esta solución simple.

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");
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.