如何将Node.JS缓冲区流块的二进制数据快速解析为结构体?

3
当我在搜索“解析nodejs二进制流”时,我看到很多例子都是当发出的数据刚好适合预期返回大小时,但是没有一个示例说明如何处理下一个块包含第一结构的剩余字节和新标题的情况。
当我期望像以下内容时,“正确”的解析二进制流方式是什么:
记录长度:4个字节 数据1:8个字节 数据2:8个字节 4字节记录[(记录长度-16)*4];
数据将以各种大小的块的形式出现。但是是否有一种方法可以调用data.readUInt32(0)并等待块填满?我不想编写一个发出字节和接收状态机的管道阶段,那样似乎非常不对。
这必须得解决,因为这是一个非常基本的概念。
能帮忙吗?
谢谢, PT
1个回答

3
嗯...这可以使用异步版本的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.

这在 node v10 或使用 babel 中非常容易,但如果您愿意,我可以在此添加不带 AsyncGenerator 的版本。

谢谢。我有点失望,因为这需要另一个外部模块来完成看似基本的事情,但这确实解决了问题。 - PeterT
我不会说它实际上需要 scramjet - 但是实现有点棘手。您可以获取源代码并查看我如何为 AsyncGenerator 实现 from,然后在没有框架的情况下重新实现它。而且它只有3个依赖项,因此膨胀很小。 - Michał Karpacki

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接