распаковать бинарный файл в стек переполнения

Я пытаюсь проанализировать двоичный файл в 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;
}
}

Я преобразовал результаты из двоичного в шестнадцатеричное, потому что мне не удавалось правильно определить позиции. В любом случае, я считаю, что этот код может быть значительно улучшен, есть идеи?

2

Решение

Это должно быть быстро, но без тестовых данных я не смог проверить это.

Ключевыми моментами являются следующие:

  • Откройте URL как двоичный файл и используйте fread (), чтобы помочь в позиционировании и разделении данных на части.
  • Используйте распаковку как для разбора заголовков, так и для тел записей.
  • Используйте ретранслятор звездочки *, чтобы быстро разобрать большие тела на предмет подписанных шорт.
  • Используйте array_values ​​() для преобразования ассоциативного массива в простой массив с числовыми ключами (например, 0, 1, 2, …).

Обновление: Я решил проблему с порядком байтов и порядков битов при сравнении маркеров, используя формат пакета «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);
0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]