356 Stimmen

Konvertierung der Dateigröße in Bytes in eine für Menschen lesbare Zeichenfolge

Ich verwende diese Funktion, um eine Dateigröße in Bytes in eine für Menschen lesbare Dateigröße zu konvertieren:

function getReadableFileSizeString(fileSizeInBytes) {
  var i = -1;
  var byteUnits = [' kB', ' MB', ' GB', ' TB', 'PB', 'EB', 'ZB', 'YB'];
  do {
    fileSizeInBytes /= 1024;
    i++;
  } while (fileSizeInBytes > 1024);

  return Math.max(fileSizeInBytes, 0.1).toFixed(1) + byteUnits[i];
}

console.log(getReadableFileSizeString(1551859712)); // output is "1.4 GB"

Es scheint jedoch, dass dies nicht zu 100 % richtig ist. Zum Beispiel:

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

Sollte das nicht sein "1.5 GB" ? Es scheint, als würde die Division durch 1024 an Präzision verlieren. Verstehe ich etwas völlig falsch oder gibt es einen besseren Weg, dies zu tun?

1voto

Israel kusayev Punkte 783

Die Typescript-Version zur Antwort von @Andrew V mit den neuen "Template Literal Types"

export const humanFileSize = (bytes: number): `${number} ${'B' | 'KB' | 'MB' | 'GB' | 'TB'}` => {
    const index = Math.floor(Math.log(bytes) / Math.log(1024));
    return `${Number((bytes / Math.pow(1024, index)).toFixed(2)) * 1} ${(['B', 'KB', 'MB', 'GB', 'TB'] as const)[index]}`;
};

0voto

Omar Omeiri Punkte 769

Ich habe eine Funktion zur Größenumwandlung geschrieben, die auch für Menschen lesbare Formate akzeptiert.

JS

const bitBase = 8;
const suffixes = {
  bit: 'b',
  b: 'B',
  kb: 'KB',
  mb: 'MB',
  gb: 'GB',
  tb: 'TB',
};
const multipliers = {
  bit: {
    toBitHr: 1,
    toB: 1 / bitBase,
    toKB: 1 / (bitBase * 1e3),
    toMB: 1 / (bitBase * 1e6),
    toGB: 1 / (bitBase * 1e9),
    toTB: 1 / (bitBase * 1e12),
  },
  B: {
    toBit: bitBase,
    toBHr: 1,
    toKB: 1 / 1e3,
    toMB: 1 / 1e6,
    toGB: 1 / 1e9,
    toTB: 1 / 1e12,
  },
  KB: {
    toBit: 1 / (bitBase * 1e3),
    toB: 1e3,
    toKBHr: 1,
    toMB: 1 / 1e3,
    toGB: 1 / 1e6,
    toTB: 1 / 1e9,
  },
  MB: {
    toBit: bitBase * 1e6,
    toB: 1e6,
    toKB: 1e3,
    toMBHr: 1,
    toGB: 1 / 1e3,
    toTB: 1 / 1e6,
  },
  GB: {
    toBit: bitBase * 1e9,
    toB: 1e9,
    toKB: 1e6,
    toMB: 1e3,
    toGBHr: 1,
    toTB: 1 / 1e3,
  },
  TB: {
    toBit: bitBase * 1e12,
    toB: 1e12,
    toKB: 1e9,
    toMB: 1e6,
    toGB: 1e3,
    toTBHr: 1,
  },
};

const round = (num, decimalPlaces) => {
  const strNum = num.toString();
  const isExp = strNum.includes('e');
  if (isExp) {
    return Number(num.toPrecision(decimalPlaces + 1));
  }

  return Number(
    `${Math.round(Number(`${num}e${decimalPlaces}`))}e${decimalPlaces * -1}`,
  );
};

function conv(
  value,
  hr,
  rnd,
  multiplier,
  suffix,
) {
  let val = value * multiplier;
  if ((value * multiplier) > Number.MAX_SAFE_INTEGER) {
    val = Number.MAX_SAFE_INTEGER;
  }
  if (val < Number.MIN_VALUE) val = 0;
  if ((rnd || rnd === 0) && val < Number.MAX_SAFE_INTEGER) {
    val = round(val, rnd);
  }
  if (hr) return `${val}${suffix}`;
  return val;
}

const MemConv = (function _() {
  return {
    bit(value) {
      return {
        toBitHr(opts = {}) {
          return conv(
            value,
            true,
            opts.round || false,
            multipliers.bit.toBitHr,
            suffixes.bit,
          );
        },
        toB(opts = {}) {
          return conv(
            value,
            opts.hr || false,
            opts.round || false,
            multipliers.bit.toB,
            suffixes.b,
          );
        },
        toKB(opts = {}) {
          return conv(
            value,
            opts.hr || false,
            opts.round || false,
            multipliers.bit.toKB,
            suffixes.kb,
          );
        },
        toMB(opts = {}) {
          return conv(
            value,
            opts.hr || false,
            opts.round || false,
            multipliers.bit.toMB,
            suffixes.mb,
          );
        },
        toGB(opts = {}) {
          return conv(
            value,
            opts.hr || false,
            opts.round || false,
            multipliers.bit.toGB,
            suffixes.gb,
          );
        },
        toTB(opts = {}) {
          return conv(
            value,
            opts.hr || false,
            opts.round || false,
            multipliers.bit.toTB,
            suffixes.tb,
          );
        },
      };
    },
    B(value) {
      return {
        toBit(opts = {}) {
          return conv(
            value,
            opts.hr || false,
            opts.round || false,
            multipliers.B.toBit,
            suffixes.bit,
          );
        },
        toBHr(opts = {}) {
          return conv(
            value,
            true,
            opts.round || false,
            multipliers.B.toBHr,
            suffixes.b,
          );
        },
        toKB(opts = {}) {
          return conv(
            value,
            opts.hr || false,
            opts.round || false,
            multipliers.B.toKB,
            suffixes.kb,
          );
        },
        toMB(opts = {}) {
          return conv(
            value,
            opts.hr || false,
            opts.round || false,
            multipliers.B.toMB,
            suffixes.mb,
          );
        },
        toGB(opts = {}) {
          return conv(
            value,
            opts.hr || false,
            opts.round || false,
            multipliers.B.toGB,
            suffixes.gb,
          );
        },
        toTB(opts = {}) {
          return conv(
            value,
            opts.hr || false,
            opts.round || false,
            multipliers.B.toTB,
            suffixes.tb,
          );
        },
      };
    },
    KB(value) {
      return {
        toBit(opts = {}) {
          return conv(
            value,
            opts.hr || false,
            opts.round || false,
            multipliers.KB.toBit,
            suffixes.bit,
          );
        },
        toB(opts = {}) {
          return conv(
            value,
            opts.hr || false,
            opts.round || false,
            multipliers.KB.toB,
            suffixes.b,
          );
        },
        toKBHr(opts = {}) {
          return conv(
            value,
            true,
            opts.round || false,
            multipliers.KB.toKBHr,
            suffixes.kb,
          );
        },
        toMB(opts = {}) {
          return conv(
            value,
            opts.hr || false,
            opts.round || false,
            multipliers.KB.toMB,
            suffixes.mb,
          );
        },
        toGB(opts = {}) {
          return conv(
            value,
            opts.hr || false,
            opts.round || false,
            multipliers.KB.toGB,
            suffixes.gb,
          );
        },
        toTB(opts = {}) {
          return conv(
            value,
            opts.hr || false,
            opts.round || false,
            multipliers.KB.toTB,
            suffixes.tb,
          );
        },
      };
    },
    MB(value) {
      return {
        toBit(opts = {}) {
          return conv(
            value,
            opts.hr || false,
            opts.round || false,
            multipliers.MB.toBit,
            suffixes.bit,
          );
        },
        toB(opts = {}) {
          return conv(
            value,
            opts.hr || false,
            opts.round || false,
            multipliers.MB.toB,
            suffixes.b,
          );
        },
        toKB(opts = {}) {
          return conv(
            value,
            opts.hr || false,
            opts.round || false,
            multipliers.MB.toKB,
            suffixes.kb,
          );
        },
        toMBHr(opts = {}) {
          return conv(
            value,
            true,
            opts.round || false,
            multipliers.MB.toMBHr,
            suffixes.mb,
          );
        },
        toGB(opts = {}) {
          return conv(
            value,
            opts.hr || false,
            opts.round || false,
            multipliers.MB.toGB,
            suffixes.gb,
          );
        },
        toTB(opts = {}) {
          return conv(
            value,
            opts.hr || false,
            opts.round || false,
            multipliers.MB.toTB,
            suffixes.tb,
          );
        },
      };
    },
    GB(value) {
      return {
        toBit(opts = {}) {
          return conv(
            value,
            opts.hr || false,
            opts.round || false,
            multipliers.GB.toBit,
            suffixes.bit,
          );
        },
        toB(opts = {}) {
          return conv(
            value,
            opts.hr || false,
            opts.round || false,
            multipliers.GB.toB,
            suffixes.b,
          );
        },
        toKB(opts = {}) {
          return conv(
            value,
            opts.hr || false,
            opts.round || false,
            multipliers.GB.toKB,
            suffixes.kb,
          );
        },
        toMB(opts = {}) {
          return conv(
            value,
            opts.hr || false,
            opts.round || false,
            multipliers.GB.toMB,
            suffixes.mb,
          );
        },
        toGBHr(opts = {}) {
          return conv(
            value,
            true,
            opts.round || false,
            multipliers.GB.toGBHr,
            suffixes.gb,
          );
        },
        toTB(opts = {}) {
          return conv(
            value,
            opts.hr || false,
            opts.round || false,
            multipliers.GB.toTB,
            suffixes.tb,
          );
        },
      };
    },
    TB(value) {
      return {
        toBit(opts = {}) {
          return conv(
            value,
            opts.hr || false,
            opts.round || false,
            multipliers.TB.toBit,
            suffixes.bit,
          );
        },
        toB(opts = {}) {
          return conv(
            value,
            opts.hr || false,
            opts.round || false,
            multipliers.TB.toB,
            suffixes.b,
          );
        },
        toKB(opts = {}) {
          return conv(
            value,
            opts.hr || false,
            opts.round || false,
            multipliers.TB.toKB,
            suffixes.kb,
          );
        },
        toMB(opts = {}) {
          return conv(
            value,
            opts.hr || false,
            opts.round || false,
            multipliers.TB.toMB,
            suffixes.mb,
          );
        },
        toGB(opts = {}) {
          return conv(
            value,
            opts.hr || false,
            opts.round || false,
            multipliers.TB.toGB,
            suffixes.gb,
          );
        },
        toTBHr(opts = {}) {
          return conv(
            value,
            true,
            opts.round || false,
            multipliers.TB.toTBHr,
            suffixes.tb,
          );
        },
      };
    },
  };
}());

const testCases = [1, 10, 150, 1000, 74839.67346];
const HRSuffixes = Object.values(suffixes);
const roundDecimals = 2;
const precision = Number(`0.${'0'.repeat(roundDecimals)}5`);
const SCIENTIFIC_NOT_NUMBER_REGXP = /[-+]?[0-9]*.?[0-9]+([eE][-+]?[0-9]+)?/g;
const SUFFIX_REGXP = /[a-z]+$/i;
const CONVERSION_TO_REGXP = /(?<=to).*(?=hr+$)|(?<=to).*(?=hr+$)?/i;

for (const conversionFrom of (Object.keys(MemConv))) {
  for (const tCase of testCases) {
    const convFunc = MemConv[conversionFrom](tCase);
    for (const [conversionToFn, f] of Object.entries(convFunc)) {
      const conversionTo = (conversionToFn.match(CONVERSION_TO_REGXP) || [conversionToFn])[0];

      const result = f();
      const humanReadable = f({ hr: true });
      const rounded = f({ round: roundDecimals });
      const roundedAndHumanReadable = f({ hr: true, round: roundDecimals });

      console.log({
        value: tCase,
        from: conversionFrom,
        to: conversionTo,
        result,
        humanReadable,
        rounded,
        roundedAndHumanReadable,
      });
    }
  }
}

TSV-Version

test

import assert from 'assert';

function test() {
  const testCases = [1, 10, 150, 1000, 74839.67346];
  const HRSuffixes = Object.values(suffixes);
  const roundDecimals = 2;
  const precision = Number(`0.${'0'.repeat(roundDecimals)}5`);
  const SCIENTIFIC_NOT_NUMBER_REGXP = /[-+]?[0-9]*.?[0-9]+([eE][-+]?[0-9]+)?/g;
  const SUFFIX_REGXP = /[a-z]+$/i;
  const CONVERSION_TO_REGXP = /(?<=to).*(?=hr+$)|(?<=to).*(?=hr+$)?/i;

  for (const conversionFrom of (Object.keys(MemConv) as (keyof typeof MemConv)[])) {
    for (const tCase of testCases) {
      const convFunc = MemConv[conversionFrom](tCase);
      for (const [conversionToFn, f] of Object.entries(convFunc)) {
        const conversionTo = (conversionToFn.match(CONVERSION_TO_REGXP) || [conversionToFn])[0];
        const expectedSuffix = suffixes[conversionTo.toLowerCase() as keyof typeof suffixes];
        const multiplier = multipliers[conversionFrom][conversionToFn as keyof typeof multipliers[typeof conversionFrom]];
        const expectedResult = tCase * multiplier > Number.MAX_SAFE_INTEGER
            ? Number.MAX_SAFE_INTEGER
            : tCase * multiplier;

        const result = f();
        const humanReadable = f({ hr: true });
        const rounded = f({ round: roundDecimals });
        const roundedAndHumanReadable = f({ hr: true, round: roundDecimals });

        const resHrNumber = Number((humanReadable.match(SCIENTIFIC_NOT_NUMBER_REGXP) || [''])[0]);
        const resHrSuffix = (humanReadable.match(SUFFIX_REGXP) || [0])[0];
        const resRoundHrNumber = Number((roundedAndHumanReadable.match(SCIENTIFIC_NOT_NUMBER_REGXP) || [''])[0]);
        const resRoundHrSuffix = (roundedAndHumanReadable.match(SUFFIX_REGXP) || [0])[0];

        if (/hr$/i.test(conversionToFn)) {
          const resNumber = Number((humanReadable.match(SCIENTIFIC_NOT_NUMBER_REGXP) || [''])[0]);
          const resSuffix = (humanReadable.match(SUFFIX_REGXP) || [0])[0];
          assert(typeof result === 'string');
          assert(typeof resSuffix === 'string');
          assert(typeof resRoundHrNumber === 'number');
          assert(typeof rounded === 'string');
          assert(result === humanReadable);
          assert(resSuffix === expectedSuffix);
          assert(resNumber <= expectedResult + precision && resNumber >= expectedResult - precision);
        } else {
          assert(typeof result === 'number');
          assert(result === resHrNumber);
          assert(typeof rounded === 'number');
          assert(result <= expectedResult + precision && result >= expectedResult - precision);
        }

        console.log({
          value: tCase,
          from: conversionFrom,
          to: conversionToFn,
          result,
          humanReadable,
          rounded,
          roundedAndHumanReadable,
        });

        assert(typeof resHrSuffix === 'string');
        assert(typeof resHrNumber === 'number');
        assert(resHrSuffix === expectedSuffix);
        assert(resHrSuffix === resRoundHrSuffix);
        assert(HRSuffixes.includes(resHrSuffix));
      }
    }
  }
}
test();

Usage

// GB to GB humanReadable
console.log(MemConv.GB(11.1942).toGBHr()); // 11.1942GB;
// GB to MB
console.log(MemConv.GB(11.1942).toMB());// 11194.2;
// MB to MB humanReadable
console.log(MemConv.MB(11.1942).toGB({ hr: true }));// 0.011194200000000001GB;
// MB to MB humanReadable with rounding
console.log(MemConv.MB(11.1942).toGB({ hr: true, round: 3 }));// 0.011GB;

0voto

Robert Mr Punkte 19

Damit die Anzahl der Dezimalstellen in der gewählten Lösung dynamisch angepasst wird, konvertieren Sie die bytes.toFixed(dp) in eine Zahl und dann zurück in eine Zeichenkette:

return Number(bytes.toFixed(dp)).toString() + " " + units[u];

Dadurch werden 100 GiB anstelle von 100,00 GiB angezeigt. Bezug auf die Frage toFixed() dynamisch in js

0voto

Sinandro Punkte 2252

Für diejenigen, die Angular gibt es ein Paket namens angular-pipes die ein entsprechendes Rohr hat:

Datei

import { BytesPipe } from 'angular-pipes';

使用方法

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

Link zu den Dokumenten .

-2voto

webolizzer Punkte 187

Let bytes = 1024 * 10 * 10 * 10;

console.log(getReadableFileSizeString(bytes))

gibt 1000.0 statt 1MB zurück

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X