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?

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

Leo
sumber
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
John Himmelman
sumber
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;
Chris Jester-Young
sumber
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]);
}
ryeguy
sumber
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.

Vonder
sumber
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";
}
guari
sumber
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
Yanni
sumber
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';
}
David Bélanger
sumber
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
SebHallin
sumber
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"
Pavel Tzonkov
sumber
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];
    }
Janith Chinthana
sumber
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];
  }
}
pengguna24087
sumber
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];
}
ZettiCaletti
sumber
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;
}
Gabriel Barcellos
sumber
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);
Yahia Mgarrech
sumber
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
sumber
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'
Madushanka Sampath
sumber
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]; 
} 
Josué Leo Moreno
sumber
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.

Ben Johnson
sumber
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
sumber
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;
  }
}
ya.teck
sumber
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%).

pengguna3690595
sumber
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';
}
Kristen
sumber
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!

EML
sumber
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];
}
?>
John Erck
sumber
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.

Juan Lago
sumber
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];
}
Steely Wing
sumber