Modo corretto per convertire le dimensioni in byte in KB, MB, GB in JavaScript


258

Ho ottenuto questo codice per convertire la dimensione in byte tramite PHP.

Ora voglio convertire quelle dimensioni in dimensioni leggibili dall'uomo usando JavaScript. Ho provato a convertire questo codice in JavaScript, che assomiglia a questo:

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

È questo il modo corretto di farlo? C'è un modo più semplice?


5
Questo in realtà si converte in GiB, MiB e KiB. Questo è standard per le dimensioni dei file, ma non sempre per le dimensioni dei dispositivi.
David Schwartz,

Risposte:


761

Da questo: ( fonte )

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: questo è il codice originale, si prega di utilizzare la versione fissa di seguito. Aliceljm non attiva più il suo codice copiato


Ora, versione fissa non minificata ed ES6: (per community)

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

Ora, versione fissa: (dalla community di Stackoverflow, + minimizzata da 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]}

Utilizzo:

// formatBytes(bytes,decimals)

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

Demo / fonte:

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>

PS: modifica k = 1000o sizes = ["..."]come vuoi ( bit o byte )


8
(1) perché byte = 0 è "n / a"? Non è solo "0 B"? (2) Math.round non ha parametri di precisione. Meglio usare(bytes / Math.pow(1024, i)).toPrecision(3)
sfigurato il

4
toFixed(n)è probabilmente più appropriato che toPrecision(n)avere una precisione costante per tutti i valori. E per evitare zeri finali (es bytesToSize(1000) // return "1.00 KB":) potremmo usare parseFloat(x). Suggerisco di sostituire l'ultima riga da: return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];. Con la modifica precedente i risultati sono: 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
Credo che la forma plurale sia usata per 0: "0 byte"
nima,

14
Direi che minify è carino, ma in una risposta di stackexchange è meglio avere il codice più dettagliato e leggibile.
donquixote,

2
KB = Kelvin byte in unità SI. che è privo di senso. Dovrebbe essere 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]);
}

risultati:

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

Puoi usare la libreria filesizejs .


Immagino che questa libreria fornisca una rappresentazione accurata, poiché 1024 byte sono 1 KB, non 1000 byte (come fornito da alcune altre soluzioni qui). Grazie @maurocchi
WM,

3
@WM questa affermazione non è vera. 1kB = 1000 byte. Ci sono 1024 byte in un Kibibyte. C'è stata confusione in passato, quindi questi due termini spiegano con precisione la differenza di dimensioni.
Brennan T

2
@BrennanT Dipende da quanti anni hai. 1 KB era 1024 byte e la maggior parte delle persone oltre una certa età lo vede ancora come tale.
kojow7,

14

Esistono 2 modi reali per rappresentare le dimensioni in relazione ai byte, sono unità SI (10 ^ 3) o unità IEC (2 ^ 10). C'è anche JEDEC ma il loro metodo è ambiguo e confuso. Ho notato che gli altri esempi presentano errori come l'utilizzo di KB anziché di KB per rappresentare un kilobyte, quindi ho deciso di scrivere una funzione che risolverà ciascuno di questi casi utilizzando l'intervallo di unità di misura attualmente accettate.

C'è un bit di formattazione alla fine che renderà il numero un po 'migliore (almeno ai miei occhi) sentiti libero di rimuovere quella formattazione se non si adatta al tuo scopo.

Godere.

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

Ecco una fodera:

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

O anche:

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


Bello! Ma se 1k è 1024 non 1000?
l2aelba,

2
Questo calcolo viene trattando 1k come 2 ^ 10, 1m come 2 ^ 20 e così via. se vuoi che 1k sia 1000 puoi cambiarlo un po 'per usare log10.
iDaN5x

1
Ecco una versione che considera 1K come 1000:val => 'BKMGT'[~~(Math.log10(val)/3)]
iDaN5x

1
Questo è carino! Ho ampliato questo per restituire l'intera stringa che volevo dalla mia funzione:i = ~~(Math.log2(b)/10); return (b/Math.pow(1024,i)).toFixed(2) + ("KMGTPEZY"[i-1]||"") + "B"
v0rtex

4

L'uso dell'operazione bit a bit sarebbe una soluzione migliore. Prova questo

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
Ottenere i byte rimanenti. Ciò fornirà la parte decimale.
Buzz LIghtyear

1
È 1024. Se hai bisogno di 100 spostare i bit di conseguenza.
Buzz LIghtyear,


3
Si prega di non prendere il codice da Internet senza capirlo o almeno testarlo. Questo è un buon esempio di codice che è semplicemente sbagliato. Prova a eseguirlo passando 3 (restituisce "1Bytes") o 400000.
Amir Haghighat

10
Caro Amir Haghighat, questo è un codice di base scritto solo da me. In javasript post 32 bit di valore intero il codice non funzionerà poiché l'intero è solo quattro byte. Queste sono informazioni di base sulla programmazione che dovresti conoscere. Stackoverflow è pensato solo per guidare le persone e non per l'alimentazione del cucchiaio.
Buzz LIghtyear,

4

Secondo la risposta di Aliceljm , ho rimosso 0 dopo il decimale:

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

Inizialmente ho usato la risposta di @Aliceljm per un progetto di caricamento di file a cui stavo lavorando, ma recentemente ho riscontrato un problema in cui un file veniva 0.98kbletto ma letto come 1.02mb. Ecco il codice aggiornato che sto utilizzando.

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

Quanto sopra verrebbe quindi chiamato dopo aver aggiunto un file in questo modo

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

Certo, Windows legge il file come essere 24.8mbma sto bene con la precisione in più.


2

Questa soluzione si basa su soluzioni precedenti, ma tiene conto sia delle unità metriche che binarie:

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

Esempi:

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

Sto aggiornando la risposta @Aliceljm qui. Poiché la cifra decimale è importante per i numeri di 1,2 cifre, arrotondare la prima cifra decimale e mantenere la prima cifra decimale. Per un numero di 3 cifre, arrotondare la posizione delle unità e ignorare tutte le cifre decimali.

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

Ecco come un byte dovrebbe essere mostrato a un essere umano:

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

Volevo solo condividere il mio contributo. Ho avuto questo problema, quindi la mia soluzione è questa. Questo convertirà le unità inferiori in unità superiori e viceversa fornirà semplicemente l'argomento toUnitefromUnit

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

Ho avuto l'idea da qui


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

Questa funzione è facile da capire e da seguire: puoi implementarla in qualsiasi lingua. È una divisione ripetuta del valore byte fino a quando non raggiungi il livello byte (unità) che è maggiore di 1kb
Kjut

Solo una breve nota, ci sono differenze tra i prefissi binari. Alcuni seguono la regola SI base 10 e altri seguono la base 2. Puoi leggere di più qui . Tuttavia, se consideri k come 1024, invece della divisione, puoi semplicemente usare l' operatore di spostamento come byteVal >> 10. Inoltre si sarebbe meglio utilizzare Math.trunc()per lanciare i numeri reali in numeri interi , invece di 1. ofdivision
Cunning

Si prega di non pubblicare solo il codice come risposta, ma anche di fornire una spiegazione su cosa fa il codice e su come risolve il problema della domanda. Le risposte con una spiegazione sono di solito di qualità superiore e hanno maggiori probabilità di attrarre voti positivi.
Mark Rotteveel,

-7

Prova questa semplice soluzione.

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");
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.