Richtige Methode zum Konvertieren der Größe in Byte in KB, MB, GB in JavaScript


258

Ich habe diesen Code bekommen, um die Größe in Bytes über PHP zu verbergen.

Jetzt möchte ich diese Größen mit JavaScript in lesbare Größen konvertieren . Ich habe versucht, diesen Code in JavaScript zu konvertieren. Das sieht folgendermaßen aus:

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

Ist das der richtige Weg, dies zu tun? Gibt es einen einfacheren Weg?


5
Dies wird tatsächlich in GiB, MiB und KiB konvertiert. Dies ist Standard für Dateigrößen, jedoch nicht immer für Gerätegrößen.
David Schwartz

Antworten:


761

Daraus: ( Quelle )

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

Hinweis: Dies ist der Originalcode. Bitte verwenden Sie die unten stehende feste Version. Aliceljm aktiviert ihren kopierten Code nicht mehr


Jetzt wurde die feste Version nicht minimiert und ES6'ed: (von der 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];
}

Jetzt feste Version: (von Stackoverflows Community, + von JSCompress minimiert )

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

Verwendung :

// formatBytes(bytes,decimals)

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

Demo / Quelle:

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: Ändern k = 1000oder sizes = ["..."]wie Sie wollen ( Bits oder Bytes )


8
(1) Warum ist Bytes = 0 "n / a"? Ist es nicht nur "0 B"? (2) Math.round hat keinen Präzisionsparameter. Ich würde besser verwenden(bytes / Math.pow(1024, i)).toPrecision(3)
disfated

4
toFixed(n)ist wahrscheinlich angemessener als toPrecision(n)eine konsistente Genauigkeit für alle Werte zu haben. Und um nachgestellte Nullen (zB :) zu vermeiden, bytesToSize(1000) // return "1.00 KB"könnten wir verwenden parseFloat(x). Ich schlage vor, die letzte Zeile durch zu ersetzen : return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];. Mit der vorherigen Änderung sind die Ergebnisse: 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
Ich glaube, Pluralform wird für 0: '0 Bytes' verwendet
Nima

14
Ich würde sagen, Minify ist nett, aber in einer Stackexchange-Antwort ist es besser, den ausführlicheren und lesbareren Code zu haben.
Donquijote

2
KB = Kelvin-Bytes in SI-Einheiten. das ist unsinnig. Es sollte kB sein.
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]);
}

Ergebnisse:

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

Sie können die Datei filesizejs verwenden.


Ich denke, diese Bibliothek liefert die genaue Darstellung, da 1024 Bytes 1 KB sind, nicht 1000 Bytes (wie von einigen anderen Lösungen hier bereitgestellt). Danke @maurocchi
WM

3
@WM diese Aussage ist nicht wahr. 1 kB = 1000 Bytes. Ein Kibibyte enthält 1024 Bytes. In der Vergangenheit gab es Verwirrung, so dass diese beiden Begriffe den Größenunterschied genau erklären.
Brennan T

2
@BrennanT Es kommt darauf an, wie alt du bist. 1 KB waren früher 1024 Bytes und die meisten Menschen über einem bestimmten Alter sehen es immer noch als solches an.
Kojow7

14

Es gibt zwei reale Möglichkeiten, Größen in Bezug auf Bytes darzustellen: SI-Einheiten (10 ^ 3) oder IEC-Einheiten (2 ^ 10). Es gibt auch JEDEC, aber ihre Methode ist mehrdeutig und verwirrend. Ich habe festgestellt, dass die anderen Beispiele Fehler aufweisen, z. B. die Verwendung von KB anstelle von kB zur Darstellung eines Kilobytes. Daher habe ich beschlossen, eine Funktion zu schreiben, die jeden dieser Fälle anhand des Bereichs der derzeit akzeptierten Maßeinheiten löst.

Am Ende befindet sich ein Formatierungsbit, mit dem die Zahl ein bisschen besser aussieht (zumindest für mein Auge). Sie können diese Formatierung jederzeit entfernen, wenn sie nicht Ihrem Zweck entspricht.

Genießen.

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

Hier ist ein Einzeiler:

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

Oder auch:

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


Schön !, Aber wenn 1k 1024 ist nicht 1000?
l2aelba

2
Diese Berechnung wird die Behandlung von 1k als 2 ^ 10, wie 1 M 2 ^ 20 und so weiter. Wenn Sie möchten, dass 1k 1000 ist, können Sie es ein wenig ändern, um log10 zu verwenden.
iDaN5x

1
Hier ist eine Version, die 1K als 1000 behandelt:val => 'BKMGT'[~~(Math.log10(val)/3)]
iDaN5x

1
Das ist nett! Ich habe dies erweitert, um die vollständige Zeichenfolge zurückzugeben, die ich von meiner Funktion wollte:i = ~~(Math.log2(b)/10); return (b/Math.pow(1024,i)).toFixed(2) + ("KMGTPEZY"[i-1]||"") + "B"
v0rtex

4

Die bitweise Operation wäre eine bessere Lösung. Versuche dies

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
Erhalten Sie die verbleibenden Bytes. Dadurch wird der Dezimalteil bereitgestellt.
Buzz LIghtyear

1
Es ist 1024. Wenn Sie 100 benötigen, verschieben Sie die Bits entsprechend.
Buzz LIghtyear


3
Bitte holen Sie sich keinen Code aus dem Internet, ohne ihn zu verstehen oder zumindest zu testen. Dies ist ein gutes Beispiel für Code, der einfach falsch ist. Versuchen Sie es auszuführen, indem Sie es 3 (gibt "1Bytes" zurück) oder 400000 übergeben.
Amir Haghighat

10
Lieber Amir Haghighat, dies ist ein grundlegender Code, der ausschließlich von mir geschrieben wurde. In Javasript Post 32 Bit Integer-Wert funktioniert der Code nicht, da Integer nur vier Bytes beträgt. Dies sind grundlegende Programmierinformationen, die Sie kennen sollten. Stackoverflow ist nur zum Führen von Personen und nicht zum Füttern von Löffeln gedacht.
Buzz LIghtyear

4

Nach Aliceljms Antwort habe ich 0 nach der Dezimalstelle entfernt:

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

Ich habe ursprünglich die Antwort von @Aliceljm für ein Datei-Upload-Projekt verwendet, an dem ich gearbeitet habe, bin aber kürzlich auf ein Problem gestoßen , bei dem eine Datei 0.98kbnur als gelesen wurde 1.02mb. Hier ist der aktualisierte Code, den ich jetzt verwende.

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

Das Obige würde dann aufgerufen, nachdem eine Datei wie folgt hinzugefügt wurde

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

Zugegeben, Windows liest die Datei als solche, 24.8mbaber ich bin mit der zusätzlichen Präzision einverstanden.


2

Diese Lösung baut auf früheren Lösungen auf, berücksichtigt jedoch sowohl metrische als auch binäre Einheiten:

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

Beispiele:

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

Ich aktualisiere @Aliceljm Antwort hier. Da die Dezimalstelle für 1,2-stellige Zahlen wichtig ist, runde ich die erste Dezimalstelle ab und behalte die erste Dezimalstelle. Bei einer dreistelligen Zahl runde ich die Einheitsstelle ab und ignoriere alle Dezimalstellen.

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

So sollte einem Menschen ein Byte gezeigt werden:

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

Ich wollte nur meine Beiträge teilen. Ich hatte dieses Problem, also ist meine Lösung dies. Dadurch werden niedrigere Einheiten in höhere Einheiten umgewandelt und umgekehrt nur das Argument toUnitundfromUnit

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

Ich habe die Idee von hier


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

Diese Funktion ist leicht zu verstehen und zu befolgen - Sie können sie in jeder Sprache implementieren. Es ist eine wiederholte Division des Byte-Werts, bis Sie die Byte-Ebene (Einheit) erreichen, die größer als 1 KB ist
Kjut

Nur eine kurze Anmerkung: Es gibt Unterschiede zwischen binären Präfixen. Einige folgen der SI-Basis-10-Regel, andere der Basis-2-Regel. Weitere Informationen finden Sie hier . Wenn Sie jedoch k als 1024 betrachten, können Sie anstelle der Division einfach einen Shift-Operator wie verwenden byteVal >> 10. Auch würden Sie besser nutzen Math.trunc()reelle Zahlen auf ganze Zahlen zu werfen , anstatt ofdivision von 1.
Cunning

Bitte posten Sie nicht nur Code als Antwort, sondern geben Sie auch eine Erklärung, was Ihr Code tut und wie er das Problem der Frage löst. Antworten mit einer Erklärung sind normalerweise von höherer Qualität und ziehen eher positive Stimmen an.
Mark Rotteveel

-7

Versuchen Sie diese einfache Problemumgehung.

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");
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.