Bonne façon de convertir la taille en octets en Ko, Mo, Go en JavaScript


258

J'ai obtenu ce code pour convertir la taille en octets via PHP.

Maintenant, je veux convertir ces tailles en tailles lisibles par l'homme à l' aide de JavaScript. J'ai essayé de convertir ce code en JavaScript, qui ressemble à ceci:

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

Est-ce la bonne façon de procéder? Existe-t-il un moyen plus simple?


5
Cela se transforme en fait en GiB, MiB et KiB. Ceci est standard pour les tailles de fichier, mais pas toujours pour les tailles de périphérique.
David Schwartz

Réponses:


761

De cela: ( source )

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

Remarque: il s'agit du code d'origine, veuillez utiliser la version fixe ci-dessous. Aliceljm n'active plus son code copié


Maintenant, version fixe non minimisée et ES6: (par communauté)

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

Maintenant, version fixe: (par la communauté de Stackoverflow, + Minified par 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]}

Utilisation:

// formatBytes(bytes,decimals)

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

Démo / source:

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: changez k = 1000ou sizes = ["..."]comme vous voulez ( bits ou octets )


8
(1) pourquoi octets = 0 est "n / a"? N'est-ce pas juste "0 B"? (2) Math.round n'a pas de paramètre de précision. Je ferais mieux d'utiliser(bytes / Math.pow(1024, i)).toPrecision(3)
disfated

4
toFixed(n)est probablement plus approprié que toPrecision(n)d'avoir une précision constante pour toutes les valeurs. Et pour éviter les zéros à la fin (ex:), bytesToSize(1000) // return "1.00 KB"nous pourrions utiliser parseFloat(x). Je suggère de remplacer la dernière ligne par: return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];. Avec le changement précédent, les résultats sont: 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
Je crois que le pluriel est utilisé pour 0: '0 octets'
nima

14
Je dirais que minify est bien, mais dans une réponse stackexchange, il est préférable d'avoir un code plus détaillé et plus lisible.
donquixote

2
Ko = octets Kelvin en unités SI. ce qui est absurde. Ce devrait être 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]);
}

Résultats:

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

Vous pouvez utiliser la bibliothèque filesizejs .


Je suppose que cette bibliothèque donne la représentation exacte, puisque 1024 octets est de 1 Ko, pas 1000 octets (comme fourni par d'autres solutions ici). Merci @maurocchi
WM

3
@WM cette affirmation n'est pas vraie. 1 Ko = 1 000 octets. Il y a 1024 octets dans un Kibibyte. Il y a eu confusion dans le passé, ces deux termes expliquent précisément la différence de taille.
Brennan T

2
@BrennanT Cela dépend de votre âge. 1 Ko était auparavant de 1024 octets et la plupart des gens au-delà d'un certain âge le considèrent toujours comme tel.
kojow7

14

Il existe 2 façons réelles de représenter les tailles par rapport aux octets, ce sont les unités SI (10 ^ 3) ou les unités CEI (2 ^ 10). Il y a aussi JEDEC mais leur méthode est ambiguë et déroutante. J'ai remarqué que les autres exemples comportaient des erreurs telles que l'utilisation de KB au lieu de kB pour représenter un kilo-octet, j'ai donc décidé d'écrire une fonction qui résoudra chacun de ces cas en utilisant la plage d'unités de mesure actuellement acceptées.

Il y a un bit de formatage à la fin qui rendra le nombre un peu meilleur (au moins à mes yeux), n'hésitez pas à supprimer ce formatage s'il ne convient pas à votre objectif.

Prendre plaisir.

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

Voici une doublure:

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

Ou même:

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


Bien! Mais si 1k vaut 1024 et non 1000?
l2aelba

2
Ce calcul est traite comme 1k ^ 2 10, 1 m comme 2 ^ 20 et ainsi de suite. si vous voulez que 1k soit 1000, vous pouvez le changer un peu pour utiliser log10.
iDaN5x

1
Voici une version qui traite 1K comme 1000:val => 'BKMGT'[~~(Math.log10(val)/3)]
iDaN5x

1
C'est sympa! J'ai développé cela pour retourner la chaîne complète que je voulais de ma fonction:i = ~~(Math.log2(b)/10); return (b/Math.pow(1024,i)).toFixed(2) + ("KMGTPEZY"[i-1]||"") + "B"
v0rtex

4

L'utilisation d'une opération au niveau du bit serait une meilleure solution. Essaye ça

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
Obtenez les octets restants. Cela fournira la partie décimale.
Buzz LIghtyear le

1
C'est 1024. Si vous avez besoin de 100, décalez les bits en conséquence.
Buzz LIghtyear


3
Veuillez ne pas saisir de code sur Internet sans le comprendre ou au moins le tester. Ceci est un bon exemple de code qui est tout simplement faux. Essayez de l'exécuter en lui passant 3 (renvoie "1 octets") ou 400000.
Amir Haghighat

10
Cher Amir Haghighat, ceci est un code de base uniquement écrit par moi. Dans javasript après 32 bits de valeur entière, le code ne fonctionnera pas car l'entier n'est que de quatre octets. Ce sont des informations de programmation de base que vous devriez connaître. Stackoverflow est uniquement destiné à guider les personnes et non à nourrir à la cuillère.
Buzz LIghtyear

4

Selon la réponse d' Aliceljm , j'ai supprimé 0 après la virgule:

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

J'ai utilisé à l' origine la réponse de @Aliceljm pour un projet de téléchargement de fichiers sur lequel je travaillais, mais j'ai récemment rencontré un problème où un fichier était en 0.98kbcours de lecture 1.02mb. Voici le code mis à jour que j'utilise maintenant.

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

Ce qui précède serait alors appelé après qu'un fichier a été ajouté comme ceci

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

Certes, Windows lit le fichier comme étant, 24.8mbmais je suis d' accord avec la précision supplémentaire.


2

Cette solution s'appuie sur les solutions précédentes, mais prend en compte à la fois les unités métriques et binaires:

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

Exemples:

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

Je mets à jour la réponse @Aliceljm ici. Étant donné que la décimale compte pour les nombres à 1,2 chiffre, je arrondis la première décimale et conserve la première décimale. Pour un nombre à 3 chiffres, j'arrondis la place des unités et j'ignore toutes les décimales.

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

Voici comment un octet doit être montré à un humain:

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

Je voulais juste partager mon avis. J'ai eu ce problème alors ma solution est la suivante. Cela convertira les unités inférieures en unités supérieures et vice versa fournira simplement l'argument toUnitetfromUnit

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

J'ai l'idée d' ici


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

Cette fonction est facile à comprendre et à suivre - vous pouvez l'implémenter dans n'importe quelle langue. C'est une division répétée de la valeur d'octet jusqu'à ce que vous atteigniez le niveau d'octet (unité) supérieur à 1
Ko

Juste une note rapide, il existe des différences entre les préfixes binaires. Certains suivent la règle SI base 10 et certains suivent la base 2. Vous pouvez en savoir plus ici . Cependant, si vous considérez k comme 1024, au lieu de la division, vous pouvez simplement utiliser l' opérateur shift comme byteVal >> 10. Aussi, vous feriez mieux d'utiliser Math.trunc()pour convertir des nombres réels en entiers au lieu de diviser par 1.
Cunning

Veuillez ne pas publier uniquement le code comme réponse, mais également fournir une explication sur ce que fait votre code et comment il résout le problème de la question. Les réponses accompagnées d'une explication sont généralement de meilleure qualité et sont plus susceptibles d'attirer des votes positifs.
Mark Rotteveel

-7

Essayez cette solution de contournement 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");
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.