Форматировать байты в килобайты, мегабайты, гигабайты


Сценарий: размер различных файлов хранится в базе данных в байтах. Каков наилучший способ форматирования этой информации о размере в килобайты, мегабайты и гигабайты? Например, у меня есть MP3, который Ubuntu отображает как "5,2 МБ (5445632 байта)". Как бы я отобразил это на веб-странице как "5,2 МБ", чтобы файлы размером менее одного мегабайта отображались в КБ, а файлы размером один гигабайт и выше отображались в ГБ?

 146
php
Author: Prix, 2010-03-24

23 answers

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

    $bytes = max($bytes, 0); 
    $pow = floor(($bytes ? log($bytes) : 0) / log(1024)); 
    $pow = min($pow, count($units) - 1); 

    // Uncomment one of the following alternatives
    // $bytes /= pow(1024, $pow);
    // $bytes /= (1 << (10 * $pow)); 

    return round($bytes, $precision) . ' ' . $units[$pow]; 
} 

(Взято из php.net , там есть много других примеров, но этот мне нравится больше всего:-)

 266
Author: Leo, 2010-03-24 18:49:07

Это реализация Криса Шутника-Янга, самая чистая, которую я когда-либо видел, в сочетании с 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
 183
Author: John Himmelman, 2016-02-15 13:38:17

Псевдокод:

$base = log($size) / log(1024);
$suffix = array("", "k", "M", "G", "T")[floor($base)];
return pow(1024, $base - floor($base)) . $suffix;
 94
Author: Chris Jester-Young, 2010-03-24 18:39:26

Это реализация Коханы, вы могли бы использовать ее:

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]);
}
 13
Author: ryeguy, 2010-03-24 18:38:16

Просто разделите его на 1024 для кб, 1024^2 для мб и 1024^3 для ГБ. Вот так просто.

 12
Author: Vonder, 2010-03-24 18:37:22

Используйте эту функцию, если вам нужен короткий код

Bcdiv до н.э.()

$size = 11485760;
echo bcdiv($size, 1048576, 0); // return: 10

echo bcdiv($size, 1048576, 2); // return: 10,9

echo bcdiv($size, 1048576, 2); // return: 10,95

echo bcdiv($size, 1048576, 3); // return: 10,953
 7
Author: Yanni, 2012-08-21 10:19:23

Просто моя альтернатива, короткая и чистая:

/**
 * @param int $bytes Number of bytes (eg. 25907)
 * @param int $precision [optional] Number of digits after the decimal point (eg. 1)
 * @return string Value converted with unit (eg. 25.3KB)
 */
function formatBytes($bytes, $precision = 2) {
    $unit = ["B", "KB", "MB", "GB"];
    $exp = floor(log($bytes, 1024)) | 0;
    return round($bytes / (pow(1024, $exp)), $precision).$unit[$exp];
}

Или, более глупо и эффективно:

function formatBytes($bytes, $precision = 2) {
    if ($bytes > pow(1024,3)) return round($bytes / pow(1024,3), $precision)."GB";
    else if ($bytes > pow(1024,2)) return round($bytes / pow(1024,2), $precision)."MB";
    else if ($bytes > 1024) return round($bytes / 1024, $precision)."KB";
    else return ($bytes)."B";
}
 6
Author: guari, 2014-04-11 11:05:53

Я знаю, что, возможно, немного поздно отвечать на этот вопрос, но больше данных никого не убьет. Вот очень быстрая функция:

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';
}
 5
Author: David Bélanger, 2016-12-14 14:05:31

Простая функция

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
 2
Author: SebHallin, 2017-06-15 06:00:53

Мне удалось выполнить следующую функцию,

    function format_size($size) {
        $mod = 1024;
        $units = explode(' ','B KB MB GB TB PB');
        for ($i = 0; $size > $mod; $i++) {
            $size /= $mod;
        }
        return round($size, 2) . ' ' . $units[$i];
    }
 1
Author: Janith Chinthana, 2013-08-18 05:16:29

Мой подход

    function file_format_size($bytes, $decimals = 2) {
  $unit_list = array('B', 'KB', 'MB', 'GB', 'PB');

  if ($bytes == 0) {
    return $bytes . ' ' . $unit_list[0];
  }

  $unit_count = count($unit_list);
  for ($i = $unit_count - 1; $i >= 0; $i--) {
    $power = $i * 10;
    if (($bytes >> $power) >= 1)
      return round($bytes / (1 << $power), $decimals) . ' ' . $unit_list[$i];
  }
}
 1
Author: user24087, 2014-04-24 07:34:12
function changeType($size, $type, $end){
    $arr = ['B', 'KB', 'MB', 'GB', 'TB'];
    $tSayi = array_search($type, $arr);
    $eSayi = array_search($end, $arr);
    $pow = $eSayi - $tSayi;
    return $size * pow(1024 * $pow) . ' ' . $end;
}

echo changeType(500, 'B', 'KB');
 1
Author: Kerem Çakır, 2015-05-29 11:47:59

Я не знаю, почему вы должны усложнять это так, как другие.

Следующий код намного проще для понимания и примерно на 25% быстрее, чем другие решения, которые используют функцию log (вызываемую функцией 20 миллионов раз с разными параметрами)

function formatBytes($bytes, $precision = 2) {
    $units = ['Byte', 'Kilobyte', 'Megabyte', 'Gigabyte', 'Terabyte'];
    $i = 0;

    while($bytes > 1024) {
        $bytes /= 1024;
        $i++;
    }
    return round($bytes, $precision) . ' ' . $units[$i];
}
 1
Author: ZettiCaletti, 2017-04-22 01:00:21

Попробуйте это;)

function bytesToSize($bytes) {
                $sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
                if ($bytes == 0) return 'n/a';
                $i = intval(floor(log($bytes) / log(1024)));
                if ($i == 0) return $bytes . ' ' . $sizes[$i]; 
                return round(($bytes / pow(1024, $i)),1,PHP_ROUND_HALF_UP). ' ' . $sizes[$i];
            }
echo bytesToSize(10000050300);
 0
Author: Yahia Mgarrech, 2013-08-24 12:25:49
function byte_format($size) {
    $bytes = array( ' KB', ' MB', ' GB', ' TB' );
    foreach ($bytes as $val) {
        if (1024 <= $size) {
            $size = $size / 1024;
            continue;
        }
        break;
    }
    return round( $size, 1 ) . $val;
}
 0
Author: mooky, 2014-08-17 08:12:49

Здесь представлена упрощенная реализация функции Drupal format_size:

/**
 * Generates a string representation for the given byte count.
 *
 * @param $size
 *   A size in bytes.
 *
 * @return
 *   A string representation of the size.
 */
function format_size($size) {
  if ($size < 1024) {
    return $size . ' B';
  }
  else {
    $size = $size / 1024;
    $units = ['KB', 'MB', 'GB', 'TB'];
    foreach ($units as $unit) {
      if (round($size, 2) >= 1024) {
        $size = $size / 1024;
      }
      else {
        break;
      }
    }
    return round($size, 2) . ' ' . $unit;
  }
}
 0
Author: ya.teck, 2015-01-19 14:06:31

Немного поздно, но немного более быстрая версия принятого ответа приведена ниже:

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%).

 0
Author: user3690595, 2015-09-18 10:48:26

Еще одна сокращенная реализация, которая может переводиться в базовое значение 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';
}
 0
Author: Christian, 2017-01-06 21:52:38

Я решил, что добавлю сетку из кода двух отправителей (используя код Джона Химмельмана, который находится в этой теме, и используя код Евгения Кузьменко), который я использую.

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

Здесь используется код Юджина для форматирования $value в байты (я храню свои данные в МБ, поэтому он преобразует мои данные: 10485760 MB в 10995116277760) - затем он использует код Джона для преобразования его в правильное отображаемое значение (10995116277760 в 10 TB).

Я нашел это действительно полезным - так что моя благодарность двум отправители!

 0
Author: EML, 2017-07-17 20:55:51

Чрезвычайно простая функция для получения человеческого размера файла.

Исходный источник: http://php.net/manual/de/function .размер файла.php#106569

Скопируйте/вставьте код:

<?php
function human_filesize($bytes, $decimals = 2) {
  $sz = 'BKMGTP';
  $factor = floor((strlen($bytes) - 1) / 3);
  return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . @$sz[$factor];
}
?>
 0
Author: John Erck, 2017-10-19 15:11:59

Я разработал свою собственную функцию, которая преобразует объем читаемой человеком памяти в разные размеры.

function convertMemorySize($strval, string $to_unit = 'b')
{
    $strval    = strtolower(str_replace(' ', '', $strval));
    $val       = floatval($strval);
    $to_unit   = strtolower(trim($to_unit))[0];
    $from_unit = str_replace($val, '', $strval);
    $from_unit = empty($from_unit) ? 'b' : trim($from_unit)[0];
    $units     = 'kmgtph';  // (k)ilobyte, (m)egabyte, (g)igabyte and so on...


    // Convert to bytes
    if ($from_unit !== 'b')
        $val *= 1024 ** (strpos($units, $from_unit) + 1);


    // Convert to unit
    if ($to_unit !== 'b')
        $val /= 1024 ** (strpos($units, $to_unit) + 1);


    return $val;
}


convertMemorySize('1024Kb', 'Mb');  // 1
convertMemorySize('1024', 'k')      // 1
convertMemorySize('5.2Mb', 'b')     // 5452595.2
convertMemorySize('10 kilobytes', 'bytes') // 10240
convertMemorySize(2048, 'k')        // By default convert from bytes, result is 2

Эта функция принимает любые сокращения объема памяти, такие как "Мегабайт, МБ, Мб, мб, м, килобайт, К, КБ, б, Терабайт, Т.....", поэтому она безопасна для опечаток.

 0
Author: Juan Lago, 2018-01-16 22:20:07
function convertToReadableSize($size)
{
  $base = log($size) / log(1024);
  $suffix = array("B", "KB", "MB", "GB", "TB");
  $f_base = floor($base);
  return round(pow(1024, $base - floor($base)), 1) . $suffix[$f_base];
}

Просто вызовите функцию

echo convertToReadableSize(1024); // Outputs '1KB'
echo convertToReadableSize(1024 * 1024); // Outputs '1MB'
 0
Author: Madushanka Sampath, 2018-01-26 11:39:31

Основываясь на ответе Лео , добавьте

  • Поддержка отрицательных
  • Поддержка 0

Если вы хотите, чтобы максимальная единица измерения была Мега, измените на $units = explode(' ', ' 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];
}
 0
Author: Steely Wing, 2018-08-30 04:10:51