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


当前回答

我将所有输入转换为字节,从而转换为所需的任何输出。此外,我使用了一个辅助函数来获取以1000或1024为基数的基数,但让它灵活地决定在流行类型上使用1024(没有' I ',比如MB而不是MiB)。

    public function converte_binario($size=0,$format_in='B',$format_out='MB',$force_in_1024=false,$force_out_1024=false,$precisao=5,$return_format=true,$decimal=',',$centena=''){
    $out = false;

    if( (is_numeric($size)) && ($size>0)){
        $in_data = $this->converte_binario_aux($format_in,$force_in_1024);
        $out_data = $this->converte_binario_aux($format_out,$force_out_1024);

        // se formato de entrada e saída foram encontrados
        if( ((isset($in_data['sucesso'])) && ($in_data['sucesso']==true)) && ((isset($out_data['sucesso'])) && ($out_data['sucesso']==true))){
            // converte formato de entrada para bytes.
            $size_bytes_in = $size * (pow($in_data['base'], $in_data['pot']));
            $size_byte_out = (pow($out_data['base'], $out_data['pot']));
            // transforma bytes na unidade de destino
            $out = number_format($size_bytes_in / $size_byte_out,$precisao,$decimal,$centena);
            if($return_format){
                $out .= $format_out;
            }
        }
    }
    return $out;
}

public function converte_binario_aux($format=false,$force_1024=false){
    $out = [];
    $out['sucesso'] = false;
    $out['base'] = 0;
    $out['pot'] = 0;
    if((is_string($format) && (strlen($format)>0))){
        $format = trim(strtolower($format));
        $units_1000 = ['b','kb' ,'mb' ,'gb' ,'tb' ,'pb' ,'eb' ,'zb' ,'yb' ];
        $units_1024 = ['b','kib','mib','gib','tib','pib','eib','zib','yib'];
        $pot = array_search($format,$units_1000);
        if( (is_numeric($pot)) && ($pot>=0)){
            $out['pot'] = $pot;
            $out['base'] = 1000;
            $out['sucesso'] = true;
        }
        else{
            $pot = array_search($format,$units_1024);
            if( (is_numeric($pot)) && ($pot>=0)){
                $out['pot'] = $pot;
                $out['base'] = 1024;
                $out['sucesso'] = true;
            }
        }
        if($force_1024){
            $out['base'] = 1024;
        }
    }
    return $out;
}

其他回答

简单的函数

function formatBytes($size, $precision = 0){
    $unit = ['Byte','KiB','MiB','GiB','TiB','PiB','EiB','ZiB','YiB'];

    for($i = 0; $size >= 1024 && $i < count($unit)-1; $i++){
        $size /= 1024;
    }

    return round($size, $precision).' '.$unit[$i];
}

echo formatBytes('1876144', 2);
//returns 1.79 MiB

这有点晚了,但一个稍微快一点的公认答案如下:

function formatBytes($bytes, $precision)
{
    $unit_list = array
    (
        'B',
        'KB',
        'MB',
        'GB',
        'TB',
    );

    $bytes = max($bytes, 0);
    $index = floor(log($bytes, 2) / 10);
    $index = min($index, count($unit_list) - 1);
    $bytes /= pow(1024, $index);

    return round($bytes, $precision) . ' ' . $unit_list[$index];
}

它更有效,因为执行一个log-2操作而不是两个log-e操作。

实际上,下面的解决方案会更快:

function formatBytes($bytes, $precision)
{
    $unit_list = array
    (
        'B',
        'KB',
        'MB',
        'GB',
        'TB',
    );

    $index_max = count($unit_list) - 1;
    $bytes = max($bytes, 0);

    for ($index = 0; $bytes >= 1024 && $index < $index_max; $index++)
    {
        $bytes /= 1024;
    }

    return round($bytes, $precision) . ' ' . $unit_list[$index];
}

这是因为由于索引是在计算值的同时计算出相应的字节数的单位。这将执行时间缩短了约35%(速度提高了55%)。

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

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

我想我会添加我正在使用的两个提交者代码的网格(使用John Himmelman的代码,这是在这个线程中,并使用Eugene Kuzmenko的代码)。

function swissConverter($value, $format = true, $precision = 2) {
    //Below converts value into bytes depending on input (specify mb, for 
    //example)
    $bytes = preg_replace_callback('/^\s*(\d+)\s*(?:([kmgt]?)b?)?\s*$/i', 
    function ($m) {
        switch (strtolower($m[2])) {
          case 't': $m[1] *= 1024;
          case 'g': $m[1] *= 1024;
          case 'm': $m[1] *= 1024;
          case 'k': $m[1] *= 1024;
        }
        return $m[1];
        }, $value);
    if(is_numeric($bytes)) {
        if($format === true) {
            //Below converts bytes into proper formatting (human readable 
            //basically)
            $base = log($bytes, 1024);
            $suffixes = array('', 'KB', 'MB', 'GB', 'TB');   

            return round(pow(1024, $base - floor($base)), $precision) .' '. 
                     $suffixes[floor($base)];
        } else {
            return $bytes;
        }
    } else {
        return NULL; //Change to prefered response
    }
}

它使用Eugene的代码将$值格式化为字节(我的数据以MB为单位,因此它将我的数据:10485760 MB转换为10995116277760)-然后它使用John的代码将其转换为适当的显示值(10995116277760转换为10 TB)。

我发现这真的很有帮助-所以我感谢两位提交者!

这是Kohana的实现,你可以使用它:

public static function bytes($bytes, $force_unit = NULL, $format = NULL, $si = TRUE)
{
    // Format string
    $format = ($format === NULL) ? '%01.2f %s' : (string) $format;

    // IEC prefixes (binary)
    if ($si == FALSE OR strpos($force_unit, 'i') !== FALSE)
    {
        $units = array('B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB');
        $mod   = 1024;
    }
    // SI prefixes (decimal)
    else
    {
        $units = array('B', 'kB', 'MB', 'GB', 'TB', 'PB');
        $mod   = 1000;
    }

    // Determine unit to use
    if (($power = array_search((string) $force_unit, $units)) === FALSE)
    {
        $power = ($bytes > 0) ? floor(log($bytes, $mod)) : 0;
    }

    return sprintf($format, $bytes / pow($mod, $power), $units[$power]);
}