Formatuj bajty do kilobajtów, megabajtów, gigabajtów

184

Scenariusz: rozmiar różnych plików jest przechowywany w bazie danych jako bajty. Jaki jest najlepszy sposób sformatowania informacji o rozmiarze na kilobajty, megabajty i gigabajty? Na przykład mam plik MP3, który Ubuntu wyświetla jako „5,2 MB (5445632 bajtów)”. Jak wyświetlić to na stronie internetowej jako „5,2 MB” ORAZ pliki o rozmiarze mniejszym niż jeden megabajt wyświetlane jako KB, a pliki o rozmiarze jednego gigabajta i więcej wyświetlane jako GB?

leepowers
źródło
3
Wierzę, że powinieneś stworzyć funkcję, która to robi. Po prostu podziel liczbę przez 1024 i spójrz na wynik. Jeśli jest to więcej niż 1024, podziel ponownie.
Ivan Nevostruev

Odpowiedzi:

319
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]; 
} 

(Zaczerpnięte z php.net , istnieje wiele innych przykładów, ale ten najbardziej mi się podoba :-)

Lew
źródło
8
Jeśli używałeś $bytes /= (1 << (10 * $pow))lub podobnego, mógłbym polubić to lepiej. :-P
Chris Jester-Young
5
Proszę bardzo: D (osobiście nie lubię bitowej arytmetyki, ponieważ trudno jest zrozumieć, jeśli się do niej nie przyzwyczaisz ...)
Leo
3
@ Justin to dlatego, że 9287695/1024/1024 to rzeczywiście 8857 :)
Mahn
30
Właściwie, to KiB, MiB, GiBa TiBponieważ jesteś dzielenie przez 1024. Jeśli podzielisz 1000to, nie byłoby i.
Devator
8
Uncomment one of the following alternativesbyło coś, czego nie zauważyłem przez 5 minut ...
Arnis Juraga
211

To jest implementacja Chrisa Jester-Younga, najczystsza, jaką kiedykolwiek widziałem, w połączeniu z php.net i precyzyjnym argumentem.

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
John Himmelman
źródło
8
ma 2 błędy - dodaj 1 do (co najmniej małych) rozmiarów plików - nie działa z 0 (zwróć NAN)
maazza
Niezłe. Czy istnieje wersja tego na odwrót?
Luke
3
marzenie lil : $suffixes = array('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'); Chcę dysku twardego Yottabyte! :-P
SpYk3HH
1
musiałem rzucić rozmiar $ dwukrotnie, aby go uruchomić. oto, co dla mnie zadziałało: funkcja formatBajty ($ rozmiar, $ precyzja = 2) {$ base = log (floatval ($ rozmiar)) / log (1024); Sufiksy $ = tablica („”, „k”, „M”, „G”, „T”); return round (pow (1024, $ base - floor ($ base)), $ precyzja). Sufiksy $ [floor ($ base)]; }
Christopher Gray
formatBytes(259748192, 3)zwraca, 259748192 MBco jest nie tak
Flip
97

Pseudo kod:

$base = log($size) / log(1024);
$suffix = array("", "k", "M", "G", "T")[floor($base)];
return pow(1024, $base - floor($base)) . $suffix;
Chris Jester-Young
źródło
Microsoft i Apple używają 1024, zależy to od twojego przypadku użycia.
Parsa Yazdani
15

To jest implementacja Kohany , możesz jej użyć:

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]);
}
ryeguy
źródło
Ich pomysł posiadania opcji pomiędzy 1024 a 1000 mocy jest dobry. Ale ta implementacja jest naprawdę dziwna. $force_uniti $siwydaje się, że robią to samo. Możesz również przekazać dowolny ciąg znaków z literą „i” $force_unit, ponieważ sprawdzają one pozycję. Formatowanie dziesiętne jest również nadmierne.
Gus Neves,
14

Po prostu podziel go przez 1024 dla KB, 1024 ^ 2 dla MB i 1024 ^ 3 dla GB. Tak proste jak to.

Vonder
źródło
8

Tylko moja alternatywa, krótka i czysta:

/**
 * @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];
}

lub bardziej głupi i skuteczny:

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";
}
guari
źródło
7

użyj tej funkcji, jeśli chcesz uzyskać krótki kod

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
Yanni
źródło
6

Wiem, że może trochę za późno odpowiedzieć na to pytanie, ale więcej danych nie zabije kogoś. Oto bardzo szybka funkcja:

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

EDYCJA: Zaktualizowałem swój post, aby uwzględnić poprawkę zaproponowaną przez 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';
}
David Bélanger
źródło
1
Otrzymujesz podwójne B (BB) dla małych wartości $ B, w ramach obejścia możesz zrobić „$ S = 'kMGTPEZY” ”, a zamiast„ @ $ S [$ F] ”zrobić” @ $ S [$ F-1] ”.
rumianek
@camomileCase Dwa lata i pół później - zaktualizowałem swoją odpowiedź. Dzięki.
David Bélanger,
4

Prosta funkcja

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
SebHallin
źródło
3

Elastyczne rozwiązanie:

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"
Pavel Tzonkov
źródło
2

Udało mi się z następującą funkcją,

    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];
    }
Janith Chinthana
źródło
2
Uwaga: K oznacza Kelvina, a k oznacza kilogramy.
ZeWaren,
2

Moje podejście

    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];
  }
}
użytkownik24087
źródło
2

Nie wiem, dlaczego miałbyś to tak skomplikować jak inni.

Poniższy kod jest znacznie prostszy do zrozumienia i około 25% szybszy niż inne rozwiązania korzystające z funkcji dziennika (zwanej funkcją 20 milionów razy z różnymi parametrami)

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];
}
ZettiCaletti
źródło
2

Zrobiłem to, konwertując wszystkie dane wejściowe na bajty, a więc konwertując na wszelkie potrzebne dane wyjściowe. Ponadto użyłem funkcji pomocniczej, aby uzyskać bazę 1000 lub 1024, ale pozostawiłem flex, aby zdecydować się na użycie 1024 na popularnym typie (bez „i”, jak MB zamiast 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;
}
Gabriel Barcellos
źródło
1

Spróbuj tego ;)

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);
Yahia Mgarrech
źródło
1
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');
Kerem Çakır
źródło
1
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];
}

Wystarczy wywołać funkcję

echo convertToReadableSize(1024); // Outputs '1KB'
echo convertToReadableSize(1024 * 1024); // Outputs '1MB'
Madushanka Sampath
źródło
1

Działa z ostatnim PHP

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); 

    $bytes /= pow(1024, $pow); 

    return round($bytes, $precision) . ' ' . $units[$pow]; 
} 
Josué Leo Moreno
źródło
Wszystko, co zostało zrobione, polega na tym samym dokładnym skopiowaniu przykładu z PHP.net, który został zrobiony przez głównego użytkownika odpowiadającego w 2010 roku dopiero 8 lat później.
JakeGould
1

Chociaż nieco przestarzała, ta biblioteka oferuje przetestowany i solidny interfejs API do konwersji:

https://github.com/gabrielelana/byte-units

Po zainstalowaniu:

\ByteUnits\Binary::bytes(1024)->format();

// Output: "1.00KiB"

I przekonwertować w innym kierunku:

\ByteUnits\Binary::parse('1KiB')->numberOfBytes();

// Output: "1024"

Oprócz podstawowej konwersji oferuje metody dodawania, odejmowania, porównywania itp.

Nie jestem w żaden sposób związany z tą biblioteką.

Ben Johnson
źródło
0
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;
}
mooky
źródło
0

Oto uproszczona implementacja funkcji format_size Drupala :

/**
 * 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;
  }
}
ya.teck
źródło
0

Jest trochę późno, ale nieco szybsza wersja zaakceptowanej odpowiedzi znajduje się poniżej:

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

Jest bardziej wydajny, ponieważ wykonuje jedną operację log-2 zamiast dwóch operacji log-e.

W rzeczywistości szybsze jest wykonanie bardziej oczywistego rozwiązania poniżej:

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

Wynika to z faktu, że ponieważ indeks jest obliczany w tym samym czasie, co wartość liczby bajtów w odpowiedniej jednostce. Skróciło to czas wykonania o około 35% (wzrost prędkości o 55%).

użytkownik 3690595
źródło
0

Inna skrócona implementacja, która może tłumaczyć na podstawową 1024 (binarną) lub podstawową 1000 (dziesiętną), a także działa z niewiarygodnie dużymi liczbami, stąd użycie biblioteki 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';
}
chrześcijanin
źródło
Tylko mała uwaga; bcpow()rzuci TypeError wyjątek, jeśli $basei $inie są ciągi znaków. Testowane na PHP w wersji 7.0.11.
David Cery,
Dzięki! Dodałem kółkowy ciąg znaków i naprawiłem błąd przesunięcia :)
Christian
0

Pomyślałem, że dodam siatkę dwóch kodów przesyłających (Używając kodu Johna Himmelmana, który jest w tym wątku i używam kodu Eugene'a Kuźmenki ), którego używam.

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

Używa kodu Eugene'a do formatowania $valuebajtów (zachowuję moje dane w MB, więc konwertuje moje dane: 10485760 MBna 10995116277760) - następnie używa kodu Johna, aby przekonwertować go na odpowiednią wartość wyświetlania ( 10995116277760na 10 TB).

Uważam to za bardzo pomocne - więc dziękuję dwóm autorom!

EML
źródło
0

Niezwykle prosta funkcja pozwalająca uzyskać rozmiar pliku ludzkiego.

Oryginalne źródło: http://php.net/manual/de/function.filesize.php#106569

Skopiuj / wklej kod:

<?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];
}
?>
John Erck
źródło
0

Opracowałem własną funkcję, która przekształca rozmiar pamięci czytelnej dla człowieka na różne rozmiary.

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

Ta funkcja akceptuje dowolny skrót wielkości pamięci, taki jak „Megabajt, MB, Mb, mb, m, kilobajt, K, KB, b, Terabajt, T ....”, więc jest bezpieczny.

Juan Lago
źródło
0

W oparciu o odpowiedź Leo , dodać

  • Wsparcie dla negatywnych
  • Wsparcie 0 <wartość <1 (np .: 0,2, spowoduje log (wartość) = liczba ujemna)

Jeśli chcesz, aby maksymalna jednostka wynosiła Mega, zmień na $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];
}
Steely Wing
źródło