Правильний спосіб перетворення розміру в байтах в KB, MB, GB в JavaScript


258

Я отримав цей код, щоб приховати розмір у байтах через PHP.

Тепер я хочу перетворити ці розміри в читані людиною розміри за допомогою JavaScript. Я спробував перетворити цей код у JavaScript, який виглядає приблизно так:

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

Це правильний спосіб зробити це? Чи є простіший спосіб?


5
Це фактично перетворюється на GiB, MiB та KiB. Це стандартно для розмірів файлів, але не завжди для розмірів пристроїв.
Девід Шварц

Відповіді:


761

З цього: ( джерело )

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

Примітка. Це оригінальний код. Будь ласка, використовуйте фіксовану версію нижче. Aliceljm більше не активує її скопійований код


Тепер виправлена ​​версія не змінена і ES6'ed: (за спільнотою)

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

Тепер, виправлена ​​версія: (спільнотою Stackoverflow, + Удосконалено 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]}

Використання:

// formatBytes(bytes,decimals)

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

Демо / джерело:

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: Змініть k = 1000або sizes = ["..."]як хочете ( біти або байти )


8
(1) чому байтами = 0 є "n / a"? Це не просто "0 B"? (2) Math.round не має параметра точності. Я краще скористаюся(bytes / Math.pow(1024, i)).toPrecision(3)
нетерпінням

4
toFixed(n)ймовірно, більш доцільно, ніж toPrecision(n)мати постійну точність для всіх значень. І щоб уникнути зворотних нулів (наприклад:), які bytesToSize(1000) // return "1.00 KB"ми могли б використати parseFloat(x). Я пропоную замінити останній рядок на: return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];. З попередньою зміною результати: 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
Я вважаю, що форма множини використовується для 0: '0 байт'
німа

14
Я б сказав, що minify - це приємно, але у відповіді на зміну stackexchange краще мати більш детальний і читабельний код.
donquixote

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

Результати:

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

Ви можете використовувати бібліотеку filesizejs .


Я думаю, ця бібліотека дає точне уявлення, оскільки 1024 байти - це 1 Кб, а не 1000 байт (як це передбачено в деяких інших рішеннях тут). Дякуємо @maurocchi
WM

3
@WM це твердження не відповідає дійсності. 1кБ = 1000 байт. У Кібібайте 1024 байти. У минулому була плутанина, тому ці два терміни точно пояснюють різницю в розмірах.
Brennan T

2
@BrennanT Це залежить від того, скільки тобі років. Раніше 1 Кб становив 1024 байти, і більшість людей старшого віку все ще сприймають його як таке.
kojow7

14

Існує 2 реальних способи представити розміри, пов'язані з байтами, це одиниці SI (10 ^ 3) або одиниці IEC (2 ^ 10). Є також JEDEC, але їх метод неоднозначний і заплутаний. Я помітив, що в інших прикладах є такі помилки, як використання KB замість kB для представлення кілобайт, тому я вирішив написати функцію, яка вирішить кожен із цих випадків, використовуючи діапазон прийнятих на сьогодні одиниць вимірювання.

В кінці є біт форматування, який зробить номер трохи кращим (принаймні, моєму оці), сміливо видаляйте це форматування, якщо воно не відповідає вашим цілям.

Насолоджуйтесь.

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

Ось один вкладиш:

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

Або навіть:

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


Приємно !, але якщо 1k - це 1024, а не 1000?
l2aelba

2
Цей розрахунок є лікування 1k як 2 ^ 10, 1 М як 2 ^ 20 і так далі. якщо ви хочете, щоб 1 к було 1000, ви можете трохи змінити його, щоб використовувати log10.
iDaN5x

1
Ось версія, яка розглядає 1K як 1000:val => 'BKMGT'[~~(Math.log10(val)/3)]
iDaN5x

1
Це добре! Я розширив це питання, щоб повернути повну рядок, яку я хотів від своєї функції:i = ~~(Math.log2(b)/10); return (b/Math.pow(1024,i)).toFixed(2) + ("KMGTPEZY"[i-1]||"") + "B"
v0rtex

4

Використання побітових операцій було б кращим рішенням. Спробуйте це

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
Отримайте байти, що залишилися. Це забезпечить десяткову частину.
Світлий рік Buzz

1
Його 1024. Якщо вам потрібно 100 змістити біт відповідно.
Buzz LIghtyear


3
Будь ласка, не захоплюйте код з Інтернету, не розуміючи його або принаймні тестуючи. Це хороший приклад коду, який просто неправильний. Спробуйте запустити його, передавши 3 (повертає "1 біт") або 400000.
Амір Хагігат

10
Шановний Аміре Гагігат, це основний код, написаний виключно мною. У посту javasript 32 біта цілого значення код не буде працювати, оскільки ціле число становить лише чотири байти. Це основні інформаційні програми, які ви повинні знати. Потік потоку призначений лише для керівництва людьми, а не годування ложкою.
Buzz LIghtyear

4

Відповідно до відповіді Aliceljm , я видалив 0 після десяткової:

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

Я спочатку використовував відповідь @Aliceljm для проекту завантаження файлів, над яким я працював, але нещодавно зіткнувся з проблемою, де файл був, 0.98kbале читався як 1.02mb. Ось оновлений код, який я зараз використовую.

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

Зазначене вище буде викликано після додавання файлу так

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

Зрозуміло, Windows читає файл як такий, 24.8mbале я добре з додатковою точністю.


2

Це рішення ґрунтується на попередніх рішеннях, але враховує як метричні, так і двійкові одиниці:

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

Приклади:

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



1

Я оновлюю відповідь @Aliceljm тут. Оскільки десяткове місце має значення для двозначних чисел, я округляю перший десяткове місце і зберігаю перший десяткове місце. Для трьохзначного числа я округляю одиниці місця і ігноруючи всі знаки після коми.

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

Ось як байт повинен бути показаний людині:

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

Я просто хотів поділитися своїм внеском. У мене була ця проблема, тому моє рішення таке. Це перетворить нижчі одиниці у вищі одиниці і навпаки просто поставить аргумент toUnitіfromUnit

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

У мене ідея звідси


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

Цю функцію легко зрозуміти та дотримуватись - її можна реалізувати будь-якою мовою. Це повторний поділ значення байта, поки ви не
досягнете

Просто швидка примітка. Існують відмінності між бінарними префіксами. Деякі дотримуються правила основи 10 SI, а інші - основи 2. Ви можете прочитати більше тут . Однак якщо ви вважаєте, що k є 1024, замість ділення, ви можете просто використовувати оператор зміни типу byteVal >> 10. Також вам краще використовувати Math.trunc()для того, щоб надати реальні числа до цілих чисел, а не поділу на 1.
Хитрий

Будь ласка, не публікуйте лише код як відповідь, але також надайте пояснення, що робить ваш код та як він вирішує проблему. Відповіді з поясненням, як правило, вищої якості і, швидше за все, залучають репутацію.
Марк Ротвевель

-7

Спробуйте це просте вирішення.

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");
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.