2017-07-28 84 views
2

我想解析一个PHP中的二进制文件,它是NoSQL DB中文档的附件。但是,在我的测试中,如果文件大小为1MB,则解包将持续大约12-15秒。该文件包含有关传感器速度的信息。在PHP中解压二进制文件

转换成十六进制二进制文件的结构如下:

BB22 1100 0015 XXXX ... 
BB22 1300 0400 20FB 5900 25FB 5910 ... 20FB 5910 
BB22 1100 0015 ... 
BB22 1300 0400 20FB 5700 25FB 5810 ... 20FB 5912 
BB22 1300 0400 20FB 5700 25FB 5810 ... 20FB 5912 
... 

标记BB22 1100包含传感器说明书中,而0015是指该信息的大小。

标记BB22 1300包含其他数据加上传感器的实际速度。接下来的两个字节0400表示该块的长度,它是1024字节。

我只对这些值的速度感兴趣,例如5900 5910 5910 5700 5810 ...

我的方法是如下:

$file = fopen($url, 'r', false, authenticationContext($url)); 
$result = stream_get_contents($file, -1); 
fclose($file); 

$hex_result = bin2hex($result); 

$markerData = 'bb2213'; 
$sensorDataUnpack= "sspeed"; // signed int16 

while(($pos = strpos($hex_result, $markerData, $pos)) !== FALSE){ 
    $pos=$pos+4; 
    for ($j=4; $j<1028; $j=$j+4) { 
     $d = unpack($sensorDataUnpack, substr($result, $pos/2+$j+2));  
     $sensorData[] = $d; 
    } 
} 

我转换的结果从二元到十六进制的,因为它不是为我工作正常获取的位置。无论如何,我相信这个代码可以有很大的改进,有什么想法?

+1

你应该真的考虑创建一个C或C++程序来完成这项工作并收集'sensorData'。然后,您只需在PHP脚本中使用适当的参数运行该程序并收集结果。它需要更多的工作,但是你的结果要快得多。当然,这需要PHP具有不被服务器提供者阻止的shell函数才能运行外部程序。您也可以尝试切换到PHP 7.x.它比旧的PHP版本要快得多。 –

+0

@ChristosLytras,可能是一个很好的方法可能是你的建议。 @CrouchingKitten,对不起。我只是遵循函数包的文档 - 有符号短(总是16位,机器字节顺序)'。你用'p'表示什么意思? –

+0

啊我现在看到了,对不起,我错过了解压缩格式代码中的命名部分。一个问题:从数据中你总是希望每秒只有一个小的int值?为什么这些被跳过? “20FB”“25FB” –

回答

0

这应该很快,但没有测试数据,我无法测试它。

的关键点是这些:

  • 打开网址为二进制,并使用FREAD()的定位,并在数据切片多达部分,以帮助。
  • 使用unpack解析标题和条目的主体。
  • 使用星号*中继器来快速解析签名短裤的大型身体。
  • 使用array_values()将关联数组转换为带数字键的简单数组(如:0,1,2,...)。

更新:我通过使用“H4”包格式以大端顺序得到一个hexa字符串来解决标记比较周围的字节顺序和比特性问题。

$sensorData = array(); 
    $file = fopen($url, 'rb', false, authenticationContext($url)); 

    while (($header = fread($file, 6)) !== false) { 
     $fields = unpack("H4marker/ssize", $header); 

     $body = fread($file, $fields["size"] * 2); 

     if ($body === false) { 
      throw new Exception("import: data stream unexpectedly ended."); 
     } 

     if ($fields["marker"] == "BB221300") { 
      $data = array_values(unpack("s*", $body)); 

      // Store only every second value. 
      for ($i = 1; $i < count($data); $i+=2) { 
       $sensorData[] = $data[$i]; 
      } 
     } 
    } 

    fclose($file);