如何从暂停的可读流读取指定字节数?Node.js场景技术咨询
如何从暂停的Node.js可读流中读取指定字节数的数据
嘿,我来帮你搞定这个问题!首先得说清楚你那段代码为啥不好使:stream.read(BytesToRead)是个同步方法,当流处于暂停状态时,内部缓冲区很可能还没攒够你要的字节数,这时候它会直接返回null,你的代码没处理这种情况,自然拿不到想要的数据。
要解决这个问题,咱们得利用可读流的异步特性——等流有足够数据可读时再尝试读取,直到凑够目标字节数。下面是一个用Promise封装的实现,你可以在异步函数里直接用:
async function readExactBytes(stream, bytesToRead) { let collectedData = Buffer.alloc(0); // 先确保流处于暂停状态(防止之前不小心启动了流动) stream.pause(); while (collectedData.length < bytesToRead) { // 每次只读取还缺的字节数,避免多拿数据 const chunk = stream.read(bytesToRead - collectedData.length); if (chunk !== null) { // 把读到的片段拼到结果里 collectedData = Buffer.concat([collectedData, chunk]); } else { // 缓冲区没数据了,等readable事件触发(有新数据进来时会触发) await new Promise(resolve => stream.once('readable', resolve)); } } return collectedData; }
这个方法的工作逻辑:
- 用一个Buffer逐步收集数据,每次只读取还需要的字节数,不会浪费缓冲区里的剩余数据
- 如果
read()返回null,说明当前没有足够数据,就通过Promise等待readable事件——这个事件会在流有新数据进入缓冲区时触发,此时再继续尝试读取 - 等收集到的数据长度刚好达到目标字节数,就返回结果
结合你的场景使用示例:
假设你用Busboy拿到了上传的MP4文件流,就可以这么用:
// 从Busboy获取到的文件流 const fileStream = ...; fileStream.pause(); // 先把流暂停,咱们手动控制读取 // 读取1024字节的片段,准备发给WebSocket const chunk = await readExactBytes(fileStream, 1024); // 通过WebSocket把这个片段发给MediaSource所在的客户端 webSocket.send(chunk); // 之后如果还要继续读,再调用readExactBytes就行
额外要注意的点:
- 如果流在读取过程中结束了(比如文件已经读完),但我们还没凑够目标字节数,这个方法会一直等待
readable事件,你可以根据需求添加超时处理,或者监听end事件来抛出错误 - 方法开头会主动暂停流,确保处于手动读取的非流动模式,避免意外的自动数据流动
- 对于给MediaSource发送数据的场景,这种分块读取的方式能精准控制每次发送的字节大小,适配WebSocket传输和MediaSource缓冲区的需求
内容的提问来源于stack exchange,提问作者Asim Siddiqui
相关产品推荐
相关产品推荐

