首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 人類可讀檔案大小格式化:高效能 formatBytes 函數最佳實踐

     編輯:PHP 相關知識

將位元組數值轉換為 KB、MB、GB 等人類可讀格式是常見需求。本文提供高效能、支援 IEC/SI 雙制、可配置精度的 formatBytes() 函數,並對比常見實作陷阱。

推薦實作:對數定位法 (O(1))

<?php
/**
 * 格式化位元組大小
 * @param int|float $bytes     位元組數 (負數視為 0)
 * @param int       $decimals  小數位數 (預設 2)
 * @param string    $sep       數值與單位分隔符 (預設空格)
 * @param bool      $binary    true=1024進制(IEC), false=1000進制(SI)
 * @return string 例:1.46 MiB、1.5 MB、1024 B
 */
function formatBytes(int|float $bytes, int $decimals = 2, string $sep = ' ', bool $binary = true): string {
    if ($bytes < 0) $bytes = 0;

    $base = $binary ? 1024 : 1000;
    $units = $binary
        ? ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']
        : ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];

    if ($bytes < $base) {
        return round($bytes, $decimals) . $sep . $units[0];
    }

    // 使用對數快速定位單位指數,避免迴圈
    $exp = (int)floor(log($bytes, $base));
    $exp = min($exp, count($units) - 1);
    $value = $bytes / ($base ** $exp);

    return round($value, $decimals) . $sep . $units[$exp];
}

// 測試
$tests = [0, 500, 1023, 1024, 1536, 1048576, 1073741824, 1099511627776, 1.2e15];
foreach ($tests as $b) {
    echo "{$b} => " . formatBytes($b) . " | " . formatBytes($b, 1, '', false) . "\n";
}
/*
0 => 0 B | 0B
500 => 500 B | 500B
1023 => 1023 B | 1.0KB
1024 => 1.00 KiB | 1.0KB
1536 => 1.50 KiB | 1.5KB
1048576 => 1.00 MiB | 1.0MB
1073741824 => 1.00 GiB | 1.0GB
1099511627776 => 1.00 TiB | 1.0TB
1.2E+15 => 1.10 PiB | 1.1PB
*/
?>

常見實作陷阱對比

實作方式代碼片段問題修正
遞迴if($b>1024) return format($b/1024,$t+1);遞迴深度有限、效能差、單位陣列索引易錯位用對數定位或迴圈
迴圈除法while($b>=1024){$b/=1024;$i++;}較慢、浮點誤差累積、需額外判斷 $b<1024 邊界可用,但不如對數快
對數定位$exp=floor(log($b,1024));極快 O(1)、無誤差累積、代碼簡潔推薦
sprintf 格式化sprintf('%.2f %s',$b,$unit)需先算好單位,配合對數法最佳可用於最終格式化

國際化支援 (intl 擴展)

<?php
function formatBytesLocalized(float $bytes, string $locale = 'zh_TW', bool $binary = true): string {
    if (!extension_loaded('intl')) return formatBytes($bytes, 2, ' ', $binary);

    $fmt = new NumberFormatter($locale, NumberFormatter::DECIMAL);
    $fmt->setAttribute(NumberFormatter::MAX_FRACTION_DIGITS, 2);
    $fmt->setAttribute(NumberFormatter::MIN_FRACTION_DIGITS, 0);

    $base = $binary ? 1024 : 1000;
    $units = $binary
        ? ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']
        : ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];

    if ($bytes < $base) return $fmt->format($bytes) . ' ' . $units[0];
    $exp = min((int)floor(log($bytes, $base)), count($units) - 1);
    $value = $bytes / ($base ** $exp);
    return $fmt->format($value) . ' ' . $units[$exp];
}

// 測試
echo formatBytesLocalized(1572864, 'zh_TW'); // 1.50 MiB
echo formatBytesLocalized(1572864, 'en_US'); // 1.5 MiB
echo formatBytesLocalized(1572864, 'de_DE'); // 1,5 MiB
echo formatBytesLocalized(1572864, 'zh_CN'); // 1.50 MiB
?>

單位標準:IEC vs SI

標準基數單位符號適用場景
IEC 60027-2 (二進制)1024KiB, MiB, GiB, TiB...記憶體、檔案大小、作業系統顯示
SI (十進制)1000KB, MB, GB, TB...硬碟廠商標示、網路頻寬、資料傳輸速率

注意:1 TB 硬碟 (SI) = 1,000,000,000,000 B ≈ 931 GiB (IEC),OS 顯示較小是正常現象。

資料庫層格式化 (MySQL 8.0.16+)


-- MySQL 內建函數
SELECT FORMAT_BYTES(1073741824); -- 1.00 GiB
SELECT FORMAT_BYTES(1000000000); -- 1000.00 MB (SI)

-- 自訂函數 (舊版本)
CREATE FUNCTION format_bytes(bytes BIGINT, binary BOOL) RETURNS VARCHAR(32)
DETERMINISTIC
BEGIN
    DECLARE units VARCHAR(64) DEFAULT 'B,KB,MB,GB,TB,PB';
    DECLARE base INT DEFAULT IF(binary, 1024, 1000);
    DECLARE i INT DEFAULT 0;
    DECLARE val DOUBLE DEFAULT bytes;
    IF bytes < base THEN RETURN CONCAT(ROUND(bytes,2),' B'); END IF;
    WHILE val >= base AND i < 5 DO
        SET val = val / base;
        SET i = i + 1;
    END WHILE;
    RETURN CONCAT(ROUND(val,2),' ',SPLIT_STR(units,',',i+1));
END;

總結

  • 推薦 對數定位法 formatBytes():O(1) 效能、無遞迴/迴圈、支援雙制、參數化配置。
  • 預設使用 IEC 單位 (KiB, MiB...) 符合作業系統慣例;硬碟/網路場景加 $binary=false。
  • 需多語系顯示時,啟用 intl 擴展使用 NumberFormatter。
  • 避免遞迴、手工 if-else 鏈、浮點誤差累積的迴圈除法。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved