web-dev-qa-db-fra.com

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 ce ne soit pas précis à 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 perd de la précision. Est-ce que je me trompe totalement ou y a-t-il une meilleure façon de le faire?

195
Hristo

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

La RAM, par exemple, est toujours mesurée en binaire. Exprimer 1551859712 sous la forme ~ 1,4 Go est donc correct.

D'autre part, les fabricants de disques durs préfèrent utiliser le format décimal. Ils l'appelleraient donc ~ 1,6 Go.

Et pour ne pas déranger, les disquettes utilisent un mélange des deux systèmes: leur 1 Mo correspond en réalité à 1024 000 octets.

35
Neil

En voici un que j'ai écrit:

function humanFileSize(bytes, si) {
    var thresh = si ? 1000 : 1024;
    if(Math.abs(bytes) < thresh) {
        return bytes + ' B';
    }
    var units = si
        ? ['kB','MB','GB','TB','PB','EB','ZB','YB']
        : ['KiB','MiB','GiB','TiB','PiB','EiB','ZiB','YiB'];
    var u = -1;
    do {
        bytes /= thresh;
        ++u;
    } while(Math.abs(bytes) >= thresh && u < units.length - 1);
    return bytes.toFixed(1)+' '+units[u];
}

par exemple.

humanFileSize(5000,true)
> "5.0 kB"
humanFileSize(5000,false)
> "4.9 KiB"
humanFileSize(-10000000000000000000000000000)
> "-8271.8 YiB"
277
mpen

Un autre mode de réalisation du 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];
};
65
Andrew V.

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 de grands nombres: Vous pouvez soit afficher eux 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 de préfixe SI, si vous Si vous divisez par 1024, vous utilisez probablement les noms de préfixe IEC. Le problème commence par diviser par 1024. De nombreuses applications utilisent le préfixe SI nom pour cela et certains utilisent les noms de préfixes IEC. La situation présente est un gâchis. 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 loop, elle est donc probablement plus rapide que d’autres fonctions.

Utilisation:

Préfixe IEC}

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 défini le 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’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, il suffit de demander

38
cocco
sizeOf = function (bytes) {
  if (bytes == 0) { return "0.00 B"; }
  var e = Math.floor(Math.log(bytes) / Math.log(1024));
  return (bytes/Math.pow(1024, e)).toFixed(2)+' '+' KMGTP'.charAt(e)+'B';
}

sizeOf (2054110009);
// => "1,91 Go" 

sizeOf (7054110);
// => "6.73 MB"

sizeOf ((3 * 1024 * 1024));
// => "3.00 MB"

15
Joshaven Potter

Solution en tant que composant ReactJS

Bytes = React.createClass({
    formatBytes() {
        var i = Math.floor(Math.log(this.props.bytes) / Math.log(1024));
        return !this.props.bytes && '0 Bytes' || (this.props.bytes / Math.pow(1024, i)).toFixed(2) + " " + ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'][i]
    },
    render () {
        return (
            <span>{ this.formatBytes() }</span>
        );
    }
});

UPDATE Pour ceux qui utilisent es6, voici une version sans état de ce même composant

const sufixes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
const getBytes = (bytes) => {
  const i = Math.floor(Math.log(bytes) / Math.log(1024));
  return !bytes && '0 Bytes' || (bytes / Math.pow(1024, i)).toFixed(2) + " " + sufixes[i];
};

const Bytes = ({ bytes }) => (<span>{ getBytes(bytes) }</span>);

Bytes.propTypes = {
  bytes: React.PropTypes.number,
};
12

Sur la base de l’idée 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> 
11
KitKat

Voici le mien - fonctionne aussi pour les très gros fichiers -_-

function formatFileSize(size)
{
    var sizes = [' Bytes', ' KB', ' MB', ' GB', ' TB', ' PB', ' EB', ' ZB', ' YB'];
    for (var i = 1; i < sizes.length; i++)
    {
        if (size < Math.pow(1024, i)) return (Math.round((size/Math.pow(1024, i-1))*100)/100) + sizes[i-1];
    }
    return size;
}
5
fiffy

Sur la base de la réponse de cocco mais légèrement désinsectisée (honnêtement, ceux avec lesquels je me sentais à l'aise sont restés/ajoutés) et ne montre pas les zéros à la fin, mais prend toujours en charge 0, espère être utile pour les autres:

function fileSizeSI(size) {
    var e = (Math.log(size) / Math.log(1e3)) | 0;
    return +(size / Math.pow(1e3, e)).toFixed(2) + ' ' + ('kMGTPEZY'[e - 1] || '') + 'B';
}


// test:
document.write([0, 23, 4322, 324232132, 22e9, 64.22e12, 76.22e15, 64.66e18, 77.11e21, 22e24].map(fileSizeSI).join('<br>'));

4
Ebrahim Byagowi
1551859712 / 1024 = 1515488
1515488 / 1024 = 1479.96875
1479.96875 / 1024 = 1.44528198242188

Votre solution est correcte. La chose importante à comprendre est que pour obtenir de 1551859712 à 1.5, vous devez effectuer des divisions de 1 000, mais les octets sont comptés dans des fragments binaires à décimaux de 1024, d'où la valeur inférieure du gigaoctet.

3
Eli

Un autre exemple similaire à ceux ici

function fileSize(b) {
    var u = 0, s=1024;
    while (b >= s || -b >= s) {
        b /= s;
        u++;
    }
    return (u ? b.toFixed(1) + ' ' : b) + ' KMGTPEZY'[u] + 'B';
}

Il mesure de manière négligeable une performance supérieure à celle des autres appareils dotés de fonctionnalités similaires.

2
Nick Kuznia

Je voulais le comportement "gestionnaire de fichiers" (par exemple, l'Explorateur Windows) où le nombre de décimales est proportionnel à la taille du nombre. Apparemment, aucune des autres réponses ne le fait.

function humanFileSize(size) {
    if (size < 1024) return size + ' B'
    let i = Math.floor(Math.log(size) / Math.log(1024))
    let num = (size / Math.pow(1024, i))
    let round = Math.round(num)
    num = round < 10 ? num.toFixed(2) : round < 100 ? num.toFixed(1) : round
    return `${num} ${'KMGTPEZY'[i-1]}B`
}

Voici quelques exemples:

humanFileSize(0)          // "0 B"
humanFileSize(1023)       // "1023 B"
humanFileSize(1024)       // "1.00 KB"
humanFileSize(10240)      // "10.0 KB"
humanFileSize(102400)     // "100 KB"
humanFileSize(1024000)    // "1000 KB"
humanFileSize(12345678)   // "11.8 MB"
humanFileSize(1234567890) // "1.15 GB"
1
Camilo Martin

Pour ceux qui utilisent Angular, il existe un paquetage appelé angular-pipes qui contient un tube pour cela:

Fichier

import { BytesPipe } from 'angular-pipes';

Utilisation

{{ 150 | bytes }} <!-- 150 B -->
{{ 1024 | bytes }} <!-- 1 KB -->
{{ 1048576 | bytes }} <!-- 1 MB -->
{{ 1024 | bytes: 0 : 'KB' }} <!-- 1 MB -->
{{ 1073741824 | bytes }} <!-- 1 GB -->
{{ 1099511627776 | bytes }} <!-- 1 TB -->
{{ 1073741824 | bytes : 0 : 'B' : 'MB' }} <!-- 1024 MB -->

Lien vers la documentation .

0
Sinandro

laissez octets = 1024 * 10 * 10 * 10;

console.log (getReadableFileSizeString (octets))

retournera 1000.0Кб au lieu de 1MB

0
webolizzer