varint算法——本质上是牺牲最高位作为标识数据结束位,达到变长编码,说白了就是贪心的分割位

时间:2023-01-27 15:53:38

varint算法,摘自:http://blog.csdn.net/liaoquesg/article/details/50897327

最近在看《大规模WEB服务开发技术》这本书中。书中提到“可变长字节码算法”的压缩数据的算法,以达到压缩数据,减少磁盘IO。 
可变长字节码算法: 
任意一个字节的最高位(下标7)均只作为标志位,而且根据字节所在位置需要乘以128的相应幂次;(我觉得这个算法只能用作自然数的压缩)

这是他的伪代码 
varint算法——本质上是牺牲最高位作为标识数据结束位,达到变长编码,说白了就是贪心的分割位

仔细研究后,我翻译成PHP版的:

    <?php
    function codeNumber($n){
        $bytes = [];
        while (true){
            array_unshift($bytes, bcmod($n, 128));
            if($n < 128){
                break;
            }else{
                $n = intval($n/128);
            }
        }
        $bytes[count($bytes) - 1] += 128;
        return $bytes;
    }

    function encode($numbers){
        $bytestream = [];
        foreach ($numbers as $n){
            $bytestream = array_merge($bytestream, codeNumber($n));
        }
        return $bytestream;
    }

    function decode($bytestream){
        $numbers = [];
        $n = 0;
        for ($i = 0; $i < count($bytestream); $i++){
            if($bytestream[$i] < 128){
                $n = 128 * $n + $bytestream[$i];
            }else{
                $n = 128 * $n + ($bytestream[$i] - 128);
                array_push($numbers, $n);
                $n = 0;
            }
        }
        return $numbers;
    }
    $a = encode([5, 130, 288]);
    var_dump($a);
    var_dump(decode($a));

打印出来的内容是:
array(5) { [0]=> int(133) [1]=> string(1) "1" [2]=> int(130) [3]=> string(1) "2" [4]=> int(160) }
array(3) { [0]=> int(5) [1]=> int(130) [2]=> int(288) }

    //写二进制
    $h = fopen('ejz3.txt', 'wb');
    foreach ($a as $k => $v)
    {
      $str3 =  pack('H*', sprintf("%02x", $v));
      fwrite($h,  $str3);
    }
    fclose($h);

    //读二进制
    $str2 = file_get_contents('ejz3.txt');
    $str2 = unpack("H*", $str2);
    $value = str_split($str2[1], 2);
    foreach ($value as $k => $v)
    {
      $value[$k] = base_convert($v, 16, 10);
    }