Преобразование размера файла в байтах в удобочитаемую строку
Я использую эту функцию для преобразования размера файла в байтах в читаемый человеком размер файла:
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 теряет точность. Я что-то совершенно не понимаю или есть лучший способ сделать это?
11 ответов:
Это зависит от того, хотите ли вы использовать двоичное или десятичное соглашение.
RAM, например, всегда измеряется в двоичном формате, поэтому выражение 1551859712 как ~1.4 GiB было бы правильным.
с другой стороны, производители жестких дисков любят использовать decimal, поэтому они назвали бы его ~1.6 GB.
и просто чтобы запутать, дискеты используют смесь двух систем - их 1 Мб на самом деле 1024000 байт.
вот один я написал:
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"
еще один вариант расчета
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]; };
вот прототип для преобразования числа в читаемую строку с соблюдением новых международных стандартов.
есть два способа представления больших чисел: вы можете либо отобразить они кратны 1000 = 10 3 (основание 10) или 1024 = 2 10 (основание 2). Если вы делите на 1000, вы, вероятно, используете имена префиксов SI, если вы разделите на 1024, вы, вероятно, используете имена префиксов IEC. Проблема начинается с деления на 1024. Много применений используют Приставки Си имена для него, а некоторые используют имена префиксов 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
, и поэтому, вероятно, быстрее, чем некоторые другие функции.использование:
префикс МЭК
console.log((186457865).fileSize()); // default IEC (power 1024) //177.82 MiB //KiB,MiB,GiB,TiB,PiB,EiB,ZiB,YiB
приставки Си
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 функция:
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));
если у вас есть вопросы о функциях, просто спросить
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"
на основе 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>
решение как компонент 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, };
вот мой - работает для действительно больших файлов тоже -_-
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; }
на основе ответ Кокко но слегка десугерифицированные (честно говоря, те, с которыми мне было удобно, остались / добавлены) и не показывают конечные нули, но все еще поддерживают 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>'));
1551859712 / 1024 = 1515488 1515488 / 1024 = 1479.96875 1479.96875 / 1024 = 1.44528198242188
ваше решение является правильным. Важно понимать, что для того, чтобы получить от
1551859712
to1.5
, вы должны сделать деления на 1000, но байты подсчитываются в двоично-десятичных кусках 1024, следовательно, почему значение гигабайта меньше.