我正在尝试用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位
答案 0 :(得分:0)
我通过编写自己的类来编写和读取不同的位长编号来解决这个问题:
$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);