TypeScript中创建流式FlatBuffers的标准实现方式是什么
JavaScript/TypeScript 多长度前缀FlatBuffer合并写入实现方案
你之前的操作误区是将多个Monster实例放到同一个Builder实例中一次性完成序列化,这种方式会将所有实例合并为单个FlatBuffer对象,自然只会生成一个总长度前缀。要实现每个Monster带独立长度前缀、且所有数据存储在同一个Uint8Array的需求,可按以下官方API实现:
实现步骤
- 第一步:预分配目标缓冲区
先根据待序列化的Monster数量、单个Monster的平均大小,预分配一个足够容纳所有数据的Uint8Array,避免多次内存申请和数组拼接开销。 - 第二步:复用Builder实例循环序列化
复用同一个FlatBuffer Builder实例,每完成一个Monster的序列化就将带长度前缀的内容写入预分配的大数组,随后重置Builder即可处理下一个实例,无需重复创建Builder对象。 - 第三步:自定义流式校验逻辑
官方flatc暂不支持为JavaScript生成原生校验函数,你可以在读取时先解析每个Monster的长度前缀,校验剩余可读长度是否充足后再执行解析,即可避免非法数据导致的越界错误。
参考代码(TypeScript)
import { Builder, ByteBuffer } from 'flatbuffers'; // 引入flatc生成的Monster类 import { Monster } from './generated/monster'; // 业务参数配置 const MONSTER_COUNT = 100; // 预估单个带前缀的Monster序列化后大小为200字节,预留30%冗余避免溢出 const PER_MONSTER_MAX_SIZE = 260; // 预分配总缓冲区 const totalBuffer = new Uint8Array(MONSTER_COUNT * PER_MONSTER_MAX_SIZE); let writeOffset = 0; // 复用单个Builder实例,避免重复初始化开销 const builder = new Builder(PER_MONSTER_MAX_SIZE); for (let i = 0; i < MONSTER_COUNT; i++) { // 重置Builder,清除上一次序列化的残留数据 builder.reset(); // 正常构建单个Monster实例 const nameOffset = builder.createString(`Monster_${i}`); Monster.startMonster(builder); Monster.addName(builder, nameOffset); Monster.addHp(builder, 100 + i); const monsterOffset = Monster.endMonster(builder); // 生成带独立长度前缀的当前Monster缓冲区 Monster.finishSizePrefixedMonsterBuffer(builder, monsterOffset); // 取出当前带前缀的Monster数据视图(无内存复制开销) const currentMonsterBuf = builder.asUint8Array(); // 写入预分配的总缓冲区 totalBuffer.set(currentMonsterBuf, writeOffset); // 更新写入偏移 writeOffset += currentMonsterBuf.length; } // 最终得到的合并缓冲区,所有Monster带独立长度前缀,可直接用于流式传输 const finalBuffer = totalBuffer.slice(0, writeOffset);
流式读取示例
const readBuf = new ByteBuffer(finalBuffer); while (readBuf.position() < readBuf.capacity()) { // 先读取4字节长度前缀 const monsterSize = readBuf.readUint32(readBuf.position()); // 自定义校验:判断剩余数据长度是否充足 if (readBuf.position() + monsterSize + 4 > readBuf.capacity()) { throw new Error('数据不完整,等待后续数据传输'); } // 解析单个Monster const monster = Monster.getSizePrefixedMonster(readBuf); // 业务逻辑处理 console.log(monster.name(), monster.hp()); }
内容的提问来源于stack exchange,提问作者sleep
相关产品推荐
相关产品推荐

