Cách chính xác để chuyển đổi kích thước theo byte thành KB, MB, GB trong JavaScript


258

Tôi đã nhận được mã này để chuyển đổi kích thước theo byte thông qua PHP.

Bây giờ tôi muốn chuyển đổi các kích thước đó thành các kích thước có thể đọc được bằng cách sử dụng JavaScript. Tôi đã cố gắng chuyển đổi mã này thành JavaScript, trông giống như thế này:

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

Đây có phải là cách chính xác để làm điều này? Có cách nào dễ hơn không?


5
Điều này thực sự chuyển đổi thành GiB, MiB và KiB. Đây là tiêu chuẩn cho kích thước tệp, nhưng không phải luôn luôn cho kích thước thiết bị.
David Schwartz

Câu trả lời:


761

Từ đây: ( nguồn )

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

Lưu ý: Đây là mã gốc, Vui lòng sử dụng phiên bản cố định bên dưới. Aliceljm không kích hoạt mã sao chép của mình nữa


Bây giờ, Phiên bản cố định chưa được tối ưu hóa và ES6'ed: (theo cộng đồng)

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

Bây giờ, Phiên bản cố định: (bởi cộng đồng của Stackoverflow, + Được tối thiểu hóa bởi 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]}

Sử dụng :

// formatBytes(bytes,decimals)

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

Bản trình diễn / nguồn:

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: Thay đổi k = 1000hoặc sizes = ["..."]theo ý muốn ( bit hoặc byte )


8
(1) tại sao byte = 0 là "n / a"? Không phải chỉ là "0 B" sao? (2) Math.round không có tham số chính xác. Tôi nên sử dụng tốt hơn(bytes / Math.pow(1024, i)).toPrecision(3)
vô hiệu hóa vào

4
toFixed(n)có lẽ thích hợp hơn là toPrecision(n)có độ chính xác nhất quán cho tất cả các giá trị. Và để tránh các số 0 ở cuối (ví dụ bytesToSize(1000) // return "1.00 KB":) chúng ta có thể sử dụng parseFloat(x). Tôi đề nghị thay thế dòng cuối cùng bằng cách : return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];. Với sự thay đổi trước đó, kết quả là: 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
Tôi tin rằng dạng số nhiều được sử dụng cho 0: '0 Byte'
nima

14
Tôi muốn nói rằng minify là tốt, nhưng trong câu trả lời stackexchange tốt hơn là có mã dài hơn và dễ đọc hơn.
donquixote

2
KB = Kelvin byte tính theo đơn vị SI. đó là vô nghĩa. Nó phải là 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]);
}

Các kết quả:

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

Bạn có thể sử dụng thư viện filesizejs .


Tôi đoán thư viện này cung cấp biểu diễn chính xác, vì 1024 byte là 1 KB, không phải 1000 byte (như được cung cấp bởi một số giải pháp khác ở đây). Cảm ơn @maurocchi
WM

3
@WM câu nói đó không đúng. 1kB = 1000 byte. Có 1024 byte trong một Kibibyte. Đã có sự nhầm lẫn trong quá khứ vì vậy hai thuật ngữ này giải thích chính xác sự khác biệt về kích thước.
Brennan T

2
@BrennanT Nó phụ thuộc vào độ tuổi của bạn. 1KB được sử dụng là 1024 byte và hầu hết mọi người trong một độ tuổi nhất định vẫn thấy nó như vậy.
kojow7

14

Có 2 cách thực sự để biểu diễn kích thước khi liên quan đến byte, đó là các đơn vị SI (10 ^ 3) hoặc đơn vị IEC (2 ^ 10). Ngoài ra còn có JEDEC nhưng phương pháp của họ rất mơ hồ và khó hiểu. Tôi nhận thấy các ví dụ khác có lỗi như sử dụng KB thay vì kB để biểu thị một kilobyte vì vậy tôi quyết định viết một hàm sẽ giải quyết từng trường hợp này bằng cách sử dụng phạm vi đơn vị đo hiện được chấp nhận.

Có một bit định dạng ở cuối sẽ làm cho số trông đẹp hơn một chút (ít nhất là trong mắt tôi) thoải mái xóa định dạng đó nếu nó không phù hợp với mục đích của bạn.

Thưởng thức.

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

Đây là một lót:

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

Hoặc thậm chí:

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


Đẹp!, Nhưng nếu 1k là 1024 chứ không phải 1000?
l2aelba

2
Tính toán này được coi 1k là 2 ^ 10, 1m là 2 ^ 20 và cứ thế. nếu bạn muốn 1k là 1000, bạn có thể thay đổi một chút để sử dụng log10.
iDaN5x

1
Đây là phiên bản có giá trị 1K là 1000:val => 'BKMGT'[~~(Math.log10(val)/3)]
iDaN5x

1
Cái này đẹp đấy! Tôi đã mở rộng về điều này để trả về chuỗi đầy đủ mà tôi muốn từ hàm của mình:i = ~~(Math.log2(b)/10); return (b/Math.pow(1024,i)).toFixed(2) + ("KMGTPEZY"[i-1]||"") + "B"
v0rtex

4

Sử dụng hoạt động bitwise sẽ là một giải pháp tốt hơn. Thử cái này

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
Lấy các byte còn lại. Điều đó sẽ cung cấp phần thập phân.
Buzz LIghtyear

1
Nó là 1024. Nếu bạn yêu cầu 100 ca bit cho phù hợp.
Buzz LIghtyear


3
Vui lòng không lấy mã từ internet mà không hiểu nó hoặc ít nhất là kiểm tra nó. Đây là một ví dụ tốt về mã đơn giản là sai. Hãy thử chạy nó bằng cách chuyển nó 3 (trả về "1Bytes") hoặc 400000.
Amir Haghighat

10
Amir Haghighat thân mến, đây là một mã cơ bản chỉ do tôi viết. Trong javasript post 32 bit giá trị số nguyên, mã sẽ không hoạt động do số nguyên chỉ có bốn byte. Đây là những infos lập trình cơ bản mà bạn nên biết. Stackoverflow chỉ có nghĩa là để hướng dẫn mọi người và không cho ăn bằng thìa.
Buzz LIghtyear

4

Theo câu trả lời của Aliceljm , tôi đã xóa 0 sau số thập phân:

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

Ban đầu tôi đã sử dụng câu trả lời của @Aliceljm cho một dự án tải lên tệp mà tôi đang thực hiện, nhưng gần đây đã gặp phải một vấn đề trong đó một tệp 0.98kbnhưng được đọc là 1.02mb. Đây là mã cập nhật tôi đang sử dụng.

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

Ở trên sẽ được gọi sau khi một tập tin được thêm vào như vậy

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

Cấp, Windows đọc tệp như hiện tại 24.8mbnhưng tôi ổn với độ chính xác cao hơn.


2

Giải pháp này dựa trên các giải pháp trước đó, nhưng có tính đến cả đơn vị số liệu và đơn vị nhị phân:

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

Ví dụ:

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

Tôi đang cập nhật câu trả lời @Aliceljm tại đây. Vì vị trí thập phân quan trọng đối với các số có 1,2 chữ số, tôi làm tròn vị trí thập phân đầu tiên và giữ vị trí thập phân đầu tiên. Đối với số có 3 chữ số, tôi làm tròn số đơn vị và bỏ qua tất cả các vị trí thập phân.

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

Đây là cách một byte nên được hiển thị cho con người:

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

Tôi chỉ muốn chia sẻ đầu vào của tôi. Tôi đã có vấn đề này vì vậy giải pháp của tôi là này. Điều này sẽ chuyển đổi các đơn vị thấp hơn thành các đơn vị cao hơn và ngược lại chỉ cung cấp đối số toUnitfromUnit

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

Tôi có ý tưởng từ đây


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

Chức năng này rất dễ hiểu và làm theo - bạn có thể thực hiện nó bằng bất kỳ ngôn ngữ nào. Đó là sự phân chia lặp lại của giá trị byte cho đến khi bạn đạt được mức byte (đơn vị) lớn hơn
1kb

Chỉ cần một lưu ý nhanh, có sự khác biệt giữa các tiền tố nhị phân. Một số theo quy tắc SI cơ sở 10 và một số theo cơ sở 2. Bạn có thể đọc thêm ở đây . Tuy nhiên, nếu bạn coi k là 1024, thay vì chia, bạn chỉ cần sử dụng toán tử shift như thế nào byteVal >> 10. Ngoài ra, bạn nên sử dụng Math.trunc()để truyền số thực cho số nguyên thay vì chia nhỏ bằng 1.
Xảo quyệt

Vui lòng không chỉ đăng mã dưới dạng câu trả lời mà còn cung cấp giải thích về mã của bạn làm gì và cách giải quyết vấn đề của câu hỏi. Câu trả lời với một lời giải thích thường có chất lượng cao hơn, và có nhiều khả năng thu hút upvote.
Mark Rotteveel

-7

Hãy thử cách giải quyết đơn giản này.

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");
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.