Я пытаюсь проанализировать двоичный файл в PHP, который является вложением документа в NoSQL DB. Однако в моих тестах, если размер файла составляет 1 МБ, распаковка длится около 12-15 секунд. Файл содержит информацию о скорости от датчика.
Бинарный файл, преобразованный в шестнадцатеричный, имеет следующую структуру:
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;
}
}
Я преобразовал результаты из двоичного в шестнадцатеричное, потому что мне не удавалось правильно определить позиции. В любом случае, я считаю, что этот код может быть значительно улучшен, есть идеи?
Это должно быть быстро, но без тестовых данных я не смог проверить это.
Ключевыми моментами являются следующие:
Обновление: Я решил проблему с порядком байтов и порядков битов при сравнении маркеров, используя формат пакета «H4», чтобы получить строку в шестнадцатеричном формате с прямым порядком байтов.
$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);
Других решений пока нет …