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?


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


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

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;

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

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.


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

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

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

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

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"

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

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

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

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

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

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

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'

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

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ą.


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

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

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


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

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!


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

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.


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];
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.