PHP 包 9 位 int 然后 10 位 int



我正在尝试用PHP编写一个程序,该程序需要9位整数(0-511)和10位整数(0-1023)的列表,并将它们作为二进制写入文件,然后将其读回。 例如:

$dataIn = array(array(275, 863), array(7, 93), array(510, 1010));
$binData = writeBin($dataIn);
$dataOut = readBin($binData);
var_dump($dataIn, $dataOut, $binData);

function writeBin($data) {
    $bin = "";
    foreach ($data as $d) {
        //                 9 bit  10 bit
        $bin .= pack('SS', $d[0], $d[1]);
    }
    return $bin;
}
function readBin($bin) {
    $bin = str_split($bin, 4);
    $data = array();
    foreach ($bin as $b) {
        $up = unpack('SS', $b); // im only getting 275, 7 and 510 here
        $data[] = $up;
    }
    return $data;
}

但是我怎样才能将它们写入二进制文件/字符串,以便每个部分的长度为 19 位,然后在读回时将其拆分为 19 位?因此,包含 10 条记录的文件应该只有 190 位

我通过编写自己的类来写入和读取不同的位长度数字到二进制来解决此问题:

$listLen = 10;
// get an array of 10 random 9 bit ints
$b9s = range(0, 511);
shuffle($b9s);
$b9s = array_slice($b9s, 0, $listLen); 
// get an array of 10 random 10 bit ints
$b10s = range(0, 1023);
shuffle($b10s);
$b10s = array_slice($b10s, 0, $listLen); 
//build array of input data
$dataIn = array();
for ($i = 0; $i < $listLen; $i++) {
    $dataIn[] = array($b9s[$i], $b10s[$i]);
}
//-------

//initialise
$bitFormat = array(9, 10);
$BC = new BinConverter($bitFormat);
//pack
$BC->addData($dataIn);
$binData = $BC->getBin();
//unpack
$BC->setBin($binData);
$dataOut = $BC->getData();
var_dump($dataOut, $binData);

Class BinConverter {
    private $bitFormat;
    private $maxSectLen;
    private $binary;
    private $binData;
    private $dataOffset;
    // $bitFormat = list of bit lengths e.g. array(9, 10)
    public function __construct($bitFormat) {
        $this->setBitFormat($bitFormat);
        $this->binary = "";
        $this->binData = "";
        $this->dataOffset = 0;
    }
    // $bitFormat = list of bit lengths e.g. array(9, 10)
    public function setBitFormat($bitFormat) {
        $bitFormat = array_merge($bitFormat);
        $this->bitFormat = $bitFormat;
        $this->maxSectLen = 0;
        foreach ($this->bitFormat as $bpos => $bf) {
            $this->bitFormat[$bpos] = (int) $bf;
            $this->maxSectLen += $this->bitFormat[$bpos];
        }
    }
    // $data = list of data sections to convert e.g. array(array(167, 89), array(62, 32), array(325, 975))
    public function addData($data) {
        foreach ($data as $d) {
            $d = array_merge($d);
            if (is_array($d) && count($d) != count($this->bitFormat)) {
                throw new Exception("Invalid data section");
            }
            foreach ($d as $dpos => $dbit) {
                $dbit = (int) $dbit;
                $tbin = decbin($dbit);
                if (strlen($tbin) > $this->bitFormat[$dpos]) {
                    throw new Exception("Data (".$dbit.") too big for ".$this->bitFormat[$dpos]." bit segment");
                }
                $this->binary .= $this->binPad($tbin, $this->bitFormat[$dpos]);
            }
        }
    }
    //returns binary representation of added data
    public function getBin() {
        $bin = "";
        if ($this->binary) {
            $bits = str_split($this->binary, 4);
            foreach ($bits as $bpos => $bit) {
                $bp = bindec($this->binPad($bit, 4));
                $bin .= pack('C', $bp);
            }
        }
        return $bin;
    }
    //$bin = string of binary data
    public function setBin($bin) {
        if (!is_string($bin)) {
            throw new Exception("Invalid binary format");
        }
        $bdata = "";
        foreach (str_split($bin) as $b) {
            $unpacked = unpack('C', $b);
            $binbit = $this->binPad(decbin($unpacked[1]), 4);
            $bdata .= $binbit;
        }
        $this->binData = $bdata;
    }
    //returns unpacked data in the current bit format
    public function getData() {
        $data = array();
        $binlen = strlen($this->binData);
        if ($binlen) {
            $bdata = $this->binData;
            $overflow = $binlen % $this->maxSectLen % 4;
            $lastbit = substr($bdata, -4);
            $overflowBit = substr($lastbit, 0, $overflow);
            $binbit = substr($lastbit, $overflow);
            $bdata = substr($bdata, 0, -4) . $binbit;
            $tdata = str_split($bdata, $this->maxSectLen);
            foreach ($tdata as $d) {
                if (strlen($d) != $this->maxSectLen) {
                    throw new Exception("Invalid binary format");
                }
                $offset = 0;
                $ds = array();
                foreach ($this->bitFormat as $bf) {
                    $ds[] = bindec(substr($d, $offset, $bf));
                    $offset += $bf;
                }
                $data[] = $ds;
            }
        }
        return $data;
    }
    //returns unpacked data in the current bit format for (int) $ni number of sections
    public function getNextSection($ni = null) {
        $data = array();
        $binlen = strlen($this->binData);
        if ($binlen) {
            $n = $ni;
            if ($n === null) {
                $n = 1;
            }
            $glen = $n*$this->maxSectLen;
            $bdata = substr($this->binData, $this->dataOffset, $glen);
            if (strlen($bdata) != $glen) {
                throw new Exception("Invalid data format used");
            }
            $this->dataOffset += $glen;
            if ($this->dataOffset+4 > $binlen) {
                $overflow = $binlen - $this->dataOffset;
                $lastbit = substr($this->binData, -4);
                $overflowBit = substr($lastbit, 0, $overflow);
                $binbit = substr($lastbit, $overflow);
                $bdata = substr($bdata, 0, -(4-$overflow)) . $binbit;
            }
            $tdata = str_split($bdata, $this->maxSectLen);
            foreach ($tdata as $d) {
                if (strlen($d) != $this->maxSectLen) {
                    throw new Exception("Invalid binary format");
                }
                $offset = 0;
                $ds = array();
                foreach ($this->bitFormat as $bf) {
                    $ds[] = bindec(substr($d, $offset, $bf));
                    $offset += $bf;
                }
                $data[] = $ds;
            }
            if ($ni === null) {
                return $data[0];
            }
        }
        return $data;
    }
    private function binPad($var, $a) {
        return str_pad($var, $a, '0', STR_PAD_LEFT);
    }
}

以及如何在一个文件中使用多种位格式的示例:

$listLen1 = rand(1, 20);
// get an array of 10 random 9 bit ints
$b9s = range(0, 511);
shuffle($b9s);
$b9s = array_slice($b9s, 0, $listLen1); 
// get an array of 10 random 10 bit ints
$b10s = range(0, 1023);
shuffle($b10s);
$b10s = array_slice($b10s, 0, $listLen1); 
//build array of input data
$dataIn1 = array();
for ($i = 0; $i < $listLen1; $i++) {
    $dataIn1[] = array($b9s[$i], $b10s[$i]);
}
$listLen2 = rand(1, 20);
// get an array of 10 random 16 bit ints
$b16s = range(0, 65535);
shuffle($b16s);
$b16s = array_slice($b16s, 0, $listLen2); 
// get an array of 10 random 8 bit ints
$b8s = range(0, 255);
shuffle($b8s);
$b8s = array_slice($b8s, 0, $listLen2); 
// get an array of 10 random 14 bit ints
$b14s = range(0, 16383);
shuffle($b14s);
$b14s = array_slice($b14s, 0, $listLen2); 
$dataIn2 = array();
for ($i = 0; $i < $listLen2; $i++) {
    $dataIn2[] = array($b16s[$i], $b8s[$i], $b14s[$i]);
}
//-------
$file = './binfile.bf';

//initialise
$bitFormat1 = array(9, 10);
$bitFormat2 = array(16, 8, 14);
$BC = new BinConvert($bitFormat1);
//pack
$BC->addData($dataIn1);
$BC->setBitFormat($bitFormat2);
$BC->addData($dataIn2);
$binData = $BC->getBin();
file_put_contents($file,$binData);

//unpack
$binData = file_get_contents($file);
$BC->setBin($binData);
$BC->setBitFormat($bitFormat1);
$dataOut1 = $BC->getNextSection($listLen1);
$BC->setBitFormat($bitFormat2);
$dataOut2 = $BC->getNextSection($listLen2);
var_dump($dataOut1, $dataOut2, $binData);

相关内容

最新更新