场景:各种文件的大小以字节的形式存储在数据库中。把这个大小信息格式化为千字节、兆字节和千兆字节的最好方法是什么?例如,我有一个MP3, Ubuntu显示为“5.2 MB(5445632字节)”。我如何在网页上显示这为“5.2 MB”,并有文件小于1兆字节显示为KB和文件1gb及以上显示为GB?


当前回答

我自己的实现,从整数大小获得格式化文件大小。简单易懂,易于扩展,以适应更大的文件-只需遵循模式。

<?php

function getFormattedFileSize($size, $precision) 
{
    switch (true) 
    {
        case ($size/1024 < 1):
            return $size.'B';
        case ($size/pow(1024, 2) < 1):
            return round($size/1024, $precision).'KB';
        case ($size/pow(1024, 3) < 1):
            return round($size/pow(1024, 2), $precision).'MB';
        case ($size/pow(1024, 4) < 1):
            return round($size/pow(1024, 3), $precision).'GB';
        case ($size/pow(1024, 5) < 1):
            return round($size/pow(1024, 4), $precision).'TB';
        default:
            return 'Error: invalid input or file is too large.';
    }
}

其他回答

根据Leo的回答,添加

对否定的支持 支持0 < value < 1(例如:0.2,会导致log(value) =负数)

如果你想要最大单位Mega,更改$units =爆炸(' ',' K M');


function formatUnit($value, $precision = 2) {
    $units = explode(' ', ' K M G T P E Z Y');

    if ($value < 0) {
        return '-' . formatUnit(abs($value));
    }

    if ($value < 1) {
        return $value . $units[0];
    }

    $power = min(
        floor(log($value, 1024)),
        count($units) - 1
    );

    return round($value / pow(1024, $power), $precision) . $units[$power];
}

我知道现在回答这个问题可能有点晚了,但是,更多的数据不会杀死一个人。这是一个非常快速的函数:

function format_filesize($B, $D=2){
    $S = 'BkMGTPEZY';
    $F = floor((strlen($B) - 1) / 3);
    return sprintf("%.{$D}f", $B/pow(1024, $F)).' '.@$S[$F].'B';
}

编辑:我更新了我的帖子,包括由camomileCase提出的修复:

function format_filesize($B, $D=2){
    $S = 'kMGTPEZY';
    $F = floor((strlen($B) - 1) / 3);
    return sprintf("%.{$D}f", $B/pow(1024, $F)).' '.@$S[$F-1].'B';
}

灵活的解决方案:

function size($size, array $options=null) {

    $o = [
        'binary' => false,
        'decimalPlaces' => 2,
        'decimalSeparator' => '.',
        'thausandsSeparator' => '',
        'maxThreshold' => false, // or thresholds key
        'suffix' => [
            'thresholds' => ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'],
            'decimal' => ' {threshold}B',
            'binary' => ' {threshold}iB',
            'bytes' => ' B'
        ]
    ];

    if ($options !== null)
        $o = array_replace_recursive($o, $options);

    $base = $o['binary'] ? 1024 : 1000;
    $exp = $size ? floor(log($size) / log($base)) : 0;

    if (($o['maxThreshold'] !== false) &&
        ($o['maxThreshold'] < $exp)
    )
        $exp = $o['maxThreshold'];

    return !$exp
        ? (round($size) . $o['suffix']['bytes'])
        : (
            number_format(
                $size / pow($base, $exp),
                $o['decimalPlaces'],
                $o['decimalSeparator'],
                $o['thausandsSeparator']
            ) .
            str_replace(
                '{threshold}',
                $o['suffix']['thresholds'][$exp],
                $o['suffix'][$o['binary'] ? 'binary' : 'decimal']
            )
        );
}

var_dump(size(disk_free_space('/')));
// string(8) "14.63 GB"
var_dump(size(disk_free_space('/'), ['binary' => true]));
// string(9) "13.63 GiB"
var_dump(size(disk_free_space('/'), ['maxThreshold' => 2]));
// string(11) "14631.90 MB"
var_dump(size(disk_free_space('/'), ['binary' => true, 'maxThreshold' => 2]));
// string(12) "13954.07 MiB"

这是Chris Jester-Young的实现,我见过的最干净的,结合了php。net的和一个精度参数。

function formatBytes($size, $precision = 2)
{
    $base = log($size, 1024);
    $suffixes = array('', 'K', 'M', 'G', 'T');   

    return round(pow(1024, $base - floor($base)), $precision) .' '. $suffixes[floor($base)];
}

echo formatBytes(24962496);
// 23.81M

echo formatBytes(24962496, 0);
// 24M

echo formatBytes(24962496, 4);
// 23.8061M

另一个压缩实现,可以转换为以1024为基数(二进制)或以1000为基数(十进制),也适用于难以置信的大数字,因此使用bc库:

function renderSize($byte,$precision=2,$mibi=true)
{
    $base = (string)($mibi?1024:1000);
    $labels = array('K','M','G','T','P','E','Z','Y');
    for($i=8;$i>=1;$i--)
        if(bccomp($byte,bcpow($base, $i))>=0)
            return bcdiv($byte,bcpow($base, $i), $precision).' '.$labels[$i-1].($mibi?'iB':'B');
    return $byte.' Byte';
}