Преобразование размера файла в байтах в удобочитаемую строку
Я использую эту функцию, чтобы преобразовать размер файла в байтах в размер файла, доступного для человека:
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 потеряет точность. Я что-то совершенно недопонимаю или есть лучший способ сделать это?
Ответы
Ответ 1
Это зависит от того, хотите ли вы использовать двоичное или десятичное соглашение.
RAM, например, всегда измеряется в двоичном формате, поэтому для выражения 1551859712 как ~ 1.4GiB будет правильным.
С другой стороны, производители жестких дисков любят использовать десятичные числа, поэтому они будут называть это ~ 1,6 ГБ.
И просто чтобы сбивать с толку, гибкие диски используют смесь двух систем - их 1 МБ на самом деле 1024000 байт.
Ответ 2
Здесь я написал:
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"
Ответ 3
Другой вариант расчета
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];
};
Ответ 4
Вот прототип для преобразования числа в читаемую строку в соответствии с новыми международными стандартами.
Существует два способа представления больших чисел: вы можете отображать их в количестве 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
i устанавливаю IEC по умолчанию, потому что я всегда использовал двоичный режим для вычисления размера файла... используя мощность 1024
Если вам просто нужен один из них в короткой функции oneliner:
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));
Если у вас есть вопросы о функциях, просто спросите
Ответ 5
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 ГБ"
SizeOf (7054110);
//= > "6.73 МБ"
sizeOf ((3 * 1024 * 1024))
//= > "3.00 MB"
Ответ 6
Решение как компонент 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>
);
}
});
ОБНОВЛЕНИЕ Для тех, кто использует 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,
};
Ответ 7
Основываясь на 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>
Ответ 8
Здесь моя - тоже работает для действительно больших файлов -_-
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;
}
Ответ 9
Основываясь на cocco 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>'));
Ответ 10
1551859712 / 1024 = 1515488
1515488 / 1024 = 1479.96875
1479.96875 / 1024 = 1.44528198242188
Ваше решение верное. Важно понять, что для перехода от 1551859712
до 1.5
вам нужно делать деления на 1000, но байты подсчитываются в двоичных-десятичных фрагментах 1024, поэтому значение Gigabyte меньше.
Ответ 11
Другой пример, аналогичный приведенному здесь
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';
}
Он измеряет пренебрежимо лучшую производительность, чем другие с аналогичными функциями.
Ответ 12
Для тех, кто использует 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 -->
Ссылка на документы.
Ответ 13
function fileSizeToString(bytes) {
// it unlikely that we'll have files bigger than this
if (bytes > 1024 * 1024 * 1024 * 1024) {
return Math.floor(bytes / (1024 * 1024 * 1024 * 1024)) + 'TB';
} else if (bytes > 1024 * 1024 * 1024) {
return Math.floor(bytes / (1024 * 1024 * 1024)) + 'GB';
} else if (bytes > 1024 * 1024) {
return Math.floor(bytes / (1024 * 1024)) + 'MB';
} else if (bytes > 1024) {
return Math.floor(bytes / 1024) + 'KB';
}
return bytes + 'B';
}
Ответ 14
Я хотел поведение "файловый менеджер" (например, Windows Explorer), где количество десятичных разрядов пропорционально размеру числа. По-видимому, ни один из других ответов не делает этого.
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"
Ответ 15
let bytes = 1024 * 10 * 10 * 10;
console.log(getReadableFileSizeString (байт))
вернет 1000,0Кб вместо 1 МБ