web-dev-qa-db-ja.com

バイト単位のファイルサイズを人間が読み取れる文字列に変換する

この関数を使用して、バイト単位のファイルサイズを人間が読めるファイルサイズに変換しています。

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

ただし、これは100%正確ではないようです。例えば:

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

これは"1.5 GB"であってはなりませんか? 1024による除算の精度が失われているようです。私は完全に何かを誤解していますか、これを行うより良い方法はありますか?

208
Hristo

これは、2進数表記と10進数表記のどちらを使用するかによって異なります。

たとえば、RAMは常にバイナリで測定されるため、1551859712を〜1.4GiBと表現するのが正しいでしょう。

一方、ハードディスクメーカーは10進数を使用することを好むため、約1.6 GBと呼びます。

紛らわしいことに、フロッピーディスクは2つのシステムを組み合わせて使用​​しています。1MBは実際には1024000バイトです。

37
Neil

ここに私が書いたものがあります:

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

例えば.

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

計算の別の実施形態

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];
};
69
Andrew V.

これは、数値を新しい国際標準に準拠した読み取り可能な文字列に変換するためのプロトタイプです。

大きな数を表すには2つの方法があります。1000= 10 3(基数10)の倍数、または1024 = 2 10(基数2)の倍数で表示できます。 1000で除算する場合はおそらくSIプレフィックス名を使用し、1024で除算する場合はおそらくIECプレフィックス名を使用します。問題は1024で除算することから始まります。多くのアプリケーションはSIプレフィックス名を使用し、一部のアプリケーションはIECプレフィックス名を使用します。現在の状況は混乱です。 SIプレフィックス名が表示されている場合、番号が1000で除算されているか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});

この関数にはloopが含まれていないため、おそらく他のいくつかの関数よりも高速です。

使用法:

IECプレフィックス

console.log((186457865).fileSize()); // default IEC (power 1024)
//177.82 MiB
//KiB,MiB,GiB,TiB,PiB,EiB,ZiB,YiB

SIプレフィックス

console.log((186457865).fileSize(1)); //1,true for SI (power 1000)
//186.46 MB 
//kB,MB,GB,TB,PB,EB,ZB,YB

IECをデフォルトとして設定したのは、ファイルのサイズを計算するために常にバイナリモードを使用していたためです。1024の累乗を使用して


短いoneliner関数でそれらの1つだけが必要な場合:

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

使用法:

console.log(fileSizeIEC(7412834521));

関数について質問があれば

39
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 GB"

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

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

16
Joshaven Potter

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 es6を使用している場合、同じコンポーネントのステートレスバージョンがあります

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

cocco のアイデアに基づいて、ここではあまりコンパクトではありませんが、できればより包括的な例を示します。

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

cocco's answer に基づいていますが、わずかに脱ゲル化されており(正直なところ、私は快適だったものが残ります/追加されます)、末尾のゼロは表示されませんが、0をサポートし、他の人に役立つことを願っています:

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>'));
5
Ebrahim Byagowi

私のものです-本当に大きなファイルでも動作します-_-

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
1551859712 / 1024 = 1515488
1515488 / 1024 = 1479.96875
1479.96875 / 1024 = 1.44528198242188

ソリューションは正しいです。重要なことは、1551859712から1.5に到達するには、1000で除算する必要がありますが、バイトは1024の2進数から10進数のチャンクでカウントされるため、ギガバイトの値が小さい理由です。

4
Eli

ここに似た別の例

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

同様の機能を備えた他の製品よりも無視できるほど優れたパフォーマンスを測定します。

4
Nick Kuznia

小数点以下の桁数が数字のサイズに比例する「ファイルマネージャー」動作(Windowsエクスプローラーなど)が必要でした。一見、これを行う他の答えはありません。

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

以下に例を示します。

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

Angularを使用する人のために、このためのパイプを持つangular-pipesというパッケージがあります。

ファイル

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

ドキュメントへのリンク

0
Sinandro

let bytes = 1024 * 10 * 10 * 10;

console.log(getReadableFileSizeString(bytes))

1MBではなく1000.0Кбを返します

0
webolizzer