Какой самый быстрый способ разбить двоичные данные блоков буферного потока Node.JS на структуры? - PullRequest
0 голосов
/ 11 сентября 2018

Поиск в Google для «разбора двоичного потока nodejs». Я вижу много примеров, когда испускаемые данные аккуратно вписываются в ожидаемый размер возвращаемого значения, но ноль примеров того, как обрабатывать случай, когда следующий блок содержит оставшиеся байты из первой структуры иновый заголовок.

Каков "правильный" способ анализа двоичных потоков, когда я ожидаю что-то вроде:

record-length: 4bytes data1: 8bytes data2: 8bytes 4-byte-records[(record-length - 16) * 4];

Данные будут поступать в виде кусков различного размера.Но есть ли способ вызвать data.readUInt32 (0) и дождаться заполнения чанка?Я бы не хотел писать этап конвейера, который испускает байты, и конечный автомат получения, который кажется очень неправильным.

Это должно быть решено, это такая базовая концепция.

Помощь?

Спасибо, PT

1 Ответ

0 голосов
/ 14 сентября 2018

Хм ... это то, что можно решить, используя асинхронную версию stream..read и поток преобразования.

Теперь вы можете написать (и это будет весело) свою собственную версию, ноФреймворк, который я написал, scramjet уже имеет это async read, и я полагаю, вы захотите сделать это легко.

Вот самое простое, что я могу придумать, используя AsyncGenerator:

const {BufferStream} = require('scramjet'); // or es6 import;
const input = BufferStream.from(getStreamFromSomewhere());

const output = DataStream.from(async function* () {
  while(true) {
    const recordLength = (await input.whenRead(4)).readUInt32(0);  // read next chunk length
    if (!recordLength) return;                                     // stream ends here;
    const data1 = await input.whenRead(8);
    const data2 = await input.whenRead(8);
    const restOfData = [];
    for (let i = 0; i < recordLength; i += 4)
      restOfData.push((await input.read(4)).readUInt32(0))

    yield {data1, data2, restOfData};
  }
})
  .catch(e => output.end()); // this is a handler for an option where any of the reads past
                             // recordLength was to return null - perhaps should be better.

Это очень просто в узле v10 или с babel, но если хотите, я могу добавить версию, не относящуюся к AsyncGenerator, здесь.

...