如何在Bun中逐行读取Stockfish子进程的ReadableStream输出?
在Bun中实现Stockfish子进程的逐行输出读取
要实现从Stockfish子进程的stdout逐行读取内容,核心是处理ReadableStream<Uint8Array>的分块数据,维护缓冲区来拼接跨块的完整行。以下是简洁实用的实现方案:
1. 封装逐行读取器类
这个类会处理流的解码、缓冲区管理,提供异步的readLine()方法:
class LineReader { #decoder = new TextDecoder(); #buffer = ""; #reader; constructor(stream) { this.#reader = stream.getReader(); } async readLine() { while (true) { // 检查缓冲区中是否有完整的行 const newlinePos = this.#buffer.indexOf("\n"); if (newlinePos !== -1) { // 提取完整行并更新缓冲区 const line = this.#buffer.slice(0, newlinePos).trimEnd(); this.#buffer = this.#buffer.slice(newlinePos + 1); return line; } // 从流中读取下一块数据 const { done, value } = await this.#reader.read(); if (done) { // 流结束时返回剩余内容(若有) const remaining = this.#buffer.trimEnd(); this.#buffer = ""; return remaining || null; } // 解码并追加到缓冲区 this.#buffer += this.#decoder.decode(value, { stream: true }); } } }
2. 结合Stockfish子进程使用
创建子进程后,实例化LineReader即可按需读取输出:
// 启动Stockfish子进程,同时绑定stdin和stdout为管道 const stockfishProcess = Bun.spawn(["stockfish"], { stdin: "pipe", stdout: "pipe", stderr: "inherit" // 可选:将stderr输出到父进程终端 }); // 初始化逐行读取器 const lineReader = new LineReader(stockfishProcess.stdout); // 示例:发送isready命令并读取响应 stockfishProcess.stdin.write("isready\n"); const readyResponse = await lineReader.readLine(); console.log(readyResponse); // 输出 "readyok" // 示例:发送uci命令并读取所有输出直到uciok stockfishProcess.stdin.write("uci\n"); let line; while ((line = await lineReader.readLine())) { console.log(line); if (line === "uciok") break; }
关键细节说明
- 分块解码处理:使用
TextDecoder的stream: true选项,确保多字节字符在分块传输时不会被截断损坏。 - 缓冲区维护:当一行数据被拆分成多个
Uint8Array块时,缓冲区会暂存未完成的内容,直到读取到完整的换行符再返回行内容。 - 异步特性:
readLine()是异步方法,需用await获取结果,适配Bun的异步IO模型。
内容的提问来源于stack exchange,提问作者LandonSchropp
相关产品推荐
相关产品推荐

