Memformat byte ke kilobyte, megabita, gigabita


184

Skenario: ukuran berbagai file disimpan dalam database sebagai byte. Apa cara terbaik untuk memformat info ukuran ini ke kilobyte, megabita dan gigabita? Misalnya saya punya MP3 yang Ubuntu tampilkan sebagai "5,2 MB (5445632 bytes)". Bagaimana saya menampilkan ini di halaman web sebagai "5,2 MB" DAN memiliki file kurang dari satu megabyte sebagai KB dan file satu gigabyte dan di atas ditampilkan sebagai GB?


3
Saya percaya Anda harus membuat fungsi melakukan ini. Bagilah angka dengan 1024 dan lihat hasilnya. Jika lebih dari 1024 maka bagilah lagi.
Ivan Nevostruev

Jawaban:


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

(Diambil dari php.net , ada banyak contoh lain di sana, tapi saya suka yang terbaik ini :-)


8
Jika Anda menggunakan $bytes /= (1 << (10 * $pow))atau sejenisnya, saya bisa menyukainya lebih baik. :-P
Chris Jester-Young

5
Ini dia: D (secara pribadi, saya tidak suka aritmatika bitwise, karena sulit dimengerti jika Anda tidak terbiasa ...)
Leo

3
@ Justin itu karena 9287695/1024/1024 memang 8.857 :)
Mahn

30
Sebenarnya, itu KiB, MiB, GiBdan TiBkarena Anda membagi dengan 1024. Jika Anda dibagi dengan 1000itu akan tanpa i.
Devator

8
Uncomment one of the following alternativesadalah sesuatu yang saya tidak perhatikan selama 5 menit ...
Arnis Juraga

211

Ini adalah implementasi Chris Jester-Young, terbersih yang pernah saya lihat, dikombinasikan dengan php.net dan argumen presisi.

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
ia memiliki 2 kesalahan - tambahkan 1 ke (setidaknya kecil) ukuran file - tidak bekerja dengan 0 (return NAN)
maazza

Bagus Apakah ada versi yang sebaliknya?
Luke

3
lil dreaming : $suffixes = array('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'); Saya ingin hard drive Yottabyte! :-P
SpYk3HH

1
saya harus melemparkan ukuran $ ke ganda untuk membuatnya berfungsi. Inilah yang bekerja untuk saya: function formatBytes ($ size, $ precision = 2) {$ base = log (floatval ($ size)) / log (1024); $ suffixes = array ('', 'k', 'M', 'G', 'T'); putaran kembali (pow (1024, $ base - floor ($ base)), $ precision). $ suffix [floor ($ base)]; }
Christopher Gray

formatBytes(259748192, 3)mengembalikan 259748192 MByang tidak benar
Balik

97

Kodesemu:

$base = log($size) / log(1024);
$suffix = array("", "k", "M", "G", "T")[floor($base)];
return pow(1024, $base - floor($base)) . $suffix;

Microsoft dan Apple menggunakan 1024, itu tergantung pada kasus penggunaan Anda.
Parsa Yazdani

15

Ini adalah implementasi Kohana , Anda bisa menggunakannya:

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

Gagasan mereka untuk memiliki opsi antara 1024 dan 1000 daya bagus. Tetapi implementasi ini benar-benar aneh. $force_unitdan $sisepertinya melakukan hal yang sama. Anda juga dapat meneruskan string apa pun dengan "i" di dalamnya $force_unit, karena mereka menguji posisi. Pemformatan desimal juga berlebihan.
Gus Neves

14

Cukup bagi dengan 1024 untuk kb, 1024 ^ 2 untuk mb dan 1024 ^ 3 untuk GB. Sesimpel itu.


8

Hanya alternatif saya, pendek dan bersih:

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

atau, lebih bodoh dan efisien:

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

gunakan fungsi ini jika Anda menginginkan kode pendek

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

Saya tahu mungkin agak terlambat untuk menjawab pertanyaan ini, tetapi lebih banyak data tidak akan membunuh seseorang. Inilah fungsi yang sangat cepat:

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

EDIT: Saya memperbarui posting saya untuk memasukkan perbaikan yang diusulkan oleh 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
Anda mendapatkan B ganda (BB) untuk nilai kecil $ B, karena pekerjaan di sekitar Anda bisa menghasilkan "$ S = 'kMGTPEZY'", dan alih-alih "@ $ S [$ F]" do "@ $ S [$ F-1] ".
camomileCase

@camomileCase Dua setengah tahun kemudian - saya memperbarui jawaban saya. Terima kasih.
David Bélanger

4

Fungsi sederhana

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

Solusi fleksibel:

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

Saya berhasil dengan fungsi berikut,

    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
Hati-hati: K untuk Kelvin dan k untuk kilo.
ZeWaren

2

Pendekatan saya

    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

Saya tidak tahu mengapa Anda harus membuatnya begitu rumit seperti yang lain.

Kode berikut jauh lebih sederhana untuk dipahami dan sekitar 25% lebih cepat daripada solusi lain yang menggunakan fungsi log (disebut fungsi 20 Mio. kali dengan parameter yang berbeda)

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

Saya melakukan ini mengubah semua input ke byte dan mengkonversi ke setiap output yang dibutuhkan. Juga, saya menggunakan fungsi bantu untuk mendapatkan basis 1000 atau 1024, tetapi membiarkannya memutuskan untuk menggunakan 1024 pada tipe populer (tanpa 'i', seperti MB, bukan 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

coba ini ;)

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

Panggil saja fungsinya

echo convertToReadableSize(1024); // Outputs '1KB'
echo convertToReadableSize(1024 * 1024); // Outputs '1MB'

1

Ini bekerja dengan PHP terakhir

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

Semua yang dilakukan di sana adalah menyalin persis sama dari contoh dari PHP.net yang dilakukan oleh penjawab utama pada tahun 2010 hanya melakukannya 8 tahun kemudian.
JakeGould

1

Meskipun agak basi, pustaka ini menawarkan API konversi yang teruji dan kuat:

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

Setelah diinstal:

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

// Output: "1.00KiB"

Dan untuk mengkonversi ke arah lain:

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

// Output: "1024"

Di luar konversi dasar, ia menawarkan metode untuk penambahan, pengurangan, perbandingan, dll.

Saya sama sekali tidak berafiliasi dengan perpustakaan ini.


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

Berikut adalah implementasi fungsi Drupal format_size yang disederhanakan :

/**
 * 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

Ini sedikit terlambat tetapi versi yang sedikit lebih cepat dari jawaban yang diterima ada di bawah ini:

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

Ini lebih efisien, karena melakukan operasi log-2 tunggal dan bukan dua operasi log-e.

Namun sebenarnya lebih cepat untuk melakukan solusi yang lebih jelas di bawah ini:

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

Ini karena indeks dihitung pada saat yang sama dengan nilai jumlah byte pada unit yang sesuai. Ini memangkas waktu eksekusi sekitar 35% (peningkatan kecepatan 55%).


0

Implementasi kental lain yang dapat menerjemahkan ke basis 1024 (biner) atau basis 1000 (desimal) dan juga bekerja dengan angka yang sangat besar karena penggunaan perpustakaan 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';
}

Hanya sedikit catatan; bcpow()akan mengeluarkan pengecualian TypeError jika $basedan $ibukan nilai string. Diuji pada PHP versi 7.0.11.
David Cery

Terima kasih! Saya menambahkan string caster dan memperbaiki bug offset :)
Christian

0

Saya pikir saya akan menambahkan dua kode submitter (Menggunakan kode John Himmelman, yang ada di utas ini, dan menggunakan kode Eugene Kuzmenko ) yang saya gunakan.

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

Ini menggunakan kode Eugene untuk memformat $valuemenjadi byte (saya menyimpan data saya di MB, jadi itu mengubah data saya: 10485760 MBmenjadi 10995116277760) - kemudian menggunakan kode John untuk mengubahnya menjadi nilai tampilan yang tepat ( 10995116277760ke 10 TB).

Saya telah menemukan ini sangat membantu - jadi terima kasih saya kepada dua submitter!


0

Fungsi yang sangat sederhana untuk mendapatkan ukuran file manusia.

Sumber asli: http://php.net/manual/de/function.filesize.php#106569

Salin / tempel kode:

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

Saya mengembangkan fungsi saya sendiri yang mengubah ukuran memori yang dapat dibaca manusia menjadi ukuran yang berbeda.

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

Fungsi ini menerima singkatan ukuran memori apa pun seperti "Megabyte, MB, Mb, mb, m, kilobyte, K, KB, b, Terabyte, T ...." sehingga aman untuk kesalahan ketik.


0

Berdasarkan jawaban Leo , tambahkan

  • Dukungan untuk yang negatif
  • Dukungan 0 <nilai <1 (Contoh: 0.2, akan menyebabkan log (nilai) = angka negatif)

Jika Anda ingin unit maks ke Mega, ubah ke $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];
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.