293 votes

Conversion de la taille du fichier en octets en chaîne lisible par l'homme

J'utilise cette fonction pour convertir une taille de fichier en octets en une taille de fichier lisible par l'homme :

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

Cependant, il semble que cela ne soit pas exact à 100%. Par exemple :

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

Cela ne devrait-il pas être "1.5 GB" ? Il semble que la division par 1024 perde en précision. Est-ce que je comprends mal quelque chose ou existe-t-il une meilleure façon de procéder ?

0 votes

@Brendan... merci ! J'apprécie :) Je vais être honnête cependant... Je n'ai pas trouvé ça tout seul. Je suis presque sûr d'avoir vu quelque chose de similaire quelque part à un moment donné.

0 votes

Votre fonction échouera sur tout ce qui est plus grand qu'environ 2^90.

0 votes

@JanusTroelsen... pourquoi cela ? donnez-moi plus de détails s'il vous plaît !

445voto

Mark Points 49079

En voici un que j'ai écrit :

/**
 * Format bytes as human-readable text.
 * 
 * @param bytes Number of bytes.
 * @param si True to use metric (SI) units, aka powers of 1000. False to use 
 *           binary (IEC), aka powers of 1024.
 * @param dp Number of decimal places to display.
 * 
 * @return Formatted string.
 */
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(1551859712))  // 1.4 GiB
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

2 votes

Je fais un ajustement : Lorsque vous évaluez le seuil, prenez la valeur absolue. De cette façon, la fonction supportera les valeurs négatives. Belle fonction ! Merci de ne pas avoir utilisé de déclaration de commutation !

26 votes

@AaronBlenkush : Quand auriez-vous une taille de fichier négative ?

25 votes

Je viens de copier votre fonction dans une feuille Google que j'utilise pour montrer le delta de taille après une opération de "nettoyage". Avant, Après, et Diff. L'opération de nettoyage a entraîné la croissance de certaines tables de la base de données, et la réduction d'autres. Par exemple, la table A a une différence de -1,95 Mo, tandis que la table B a une différence de 500 Ko. Donc : positif et négatif :-)

112voto

Andrew V. Points 71

Une autre forme de calcul

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

9 votes

Semble ne pas gérer le 0

5 votes

Il gère ou non 0 ? Après tout, ceci avec un if(size == 0) {} else {} est quand même plus élégant que la plupart de ce que j'ai vu.

18 votes

En changeant la première ligne en var i = size == 0 ? 0 : Math.floor( Math.log(size) / Math.log(1024) ); semble faire l'affaire si elle est égale à 0. Elle renvoie "0 B".

56voto

Neil Points 24938

Tout dépend si vous voulez utiliser la convention binaire ou décimale.

La RAM, par exemple, est toujours mesurée en binaire, donc exprimer 1551859712 comme ~1,4GiB serait correct.

D'un autre côté, les fabricants de disques durs aiment utiliser la virgule, et ils l'appelleraient donc ~1,6 Go.

Et pour ne rien gâcher, les disquettes utilisent un mélange des deux systèmes : leur 1 Mo correspond en fait à 1024 000 octets.

6 votes

Très drôle ;-) "Pour ne rien gâcher, les disquettes utilisent un mélange des deux systèmes - leur 1MB est en fait 1024000 octets."

1 votes

C'est vrai, les tailles de RAM sont mesurées en utilisant les unités IEC, les tailles de disques en utilisant le système métrique il y a un module npm isomorphe pour convertir les deux : taille d'octet

36voto

cocco Points 3958

Voici un prototype permettant de convertir un nombre en une chaîne lisible respectant les nouvelles normes internationales.

Il y a deux façons de représenter les grands nombres : Vous pouvez soit les afficher en multiples de 1000 = 10 3 (base 10) ou 1024 = 2 10 (base 2). Si Si vous divisez par 1000, vous utilisez probablement les noms préfixes SI, si vous si vous divisez par 1024, vous utilisez probablement les préfixes CEI. Le problème commence avec la division par 1024. De nombreuses applications utilisent le préfixe SI et d'autres utilisent les noms de préfixe CEI. La situation actuelle est un désordre. Si vous voyez des noms de préfixe SI, vous ne savez pas si le nombre est divisé par 1000 ou 1024

https://wiki.ubuntu.com/UnitsPolicy

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

Cette fonction ne contient pas de loop et elle est donc probablement plus rapide que d'autres fonctions.

Utilisation :

Préfixe CEI

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

Préfixe SI

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

J'ai mis l'IEC par défaut car j'ai toujours utilisé le mode binaire pour calculer la taille d'un fichier... en utilisant la puissance de 1024.


Si vous voulez juste l'un d'entre eux dans une fonction oneliner courte :

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

Utilisation :

console.log(fileSizeIEC(7412834521));

Si vous avez des questions sur les fonctions, n'hésitez pas à les poser.

0 votes

Très beau code compact, j'ajouterais personnellement quelques caractères supplémentaires pour le contrôle des décimales.

0 votes

Bonjour ! En fait, le code est tel que je l'ai écrit la première fois dans jsfiddle. Ces dernières années, j'ai appris à utiliser la sténographie et le bitwise. Appareils mobiles lents, internet lent, peu d'espace... en faisant cela j'ai gagné beaucoup de temps. Mais ce n'est pas tout, la performance globale a augmenté drastiquement dans tous les navigateurs et le code entier se charge beaucoup plus rapidement ... je n'utilise pas jquery pour ne pas avoir à charger 100kb à chaque fois. Je dois aussi dire que j'écris aussi du javascript dans des microcontrôleurs, des Smart TV, des consoles de jeux. Ceux-ci ont un espace limité (MCU), des performances limitées (SmartTV) et naturellement une connexion parfois lente (Mobile).

0 votes

Cela dit, j'espère que vous comprenez mon choix. Tout ce que je peux faire, c'est expliquer ce que vous ne comprenez pas ou, à l'inverse, je suis toujours heureux d'apprendre de nouvelles choses. S'il y a quelque chose dans mon code qui pourrait améliorer les performances ou économiser de l'espace, je suis heureux de l'entendre.

11voto

KitKat Points 311

Sur la base de cocco Voici un exemple moins compact, mais, espérons-le, plus complet.

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X