参数“stdio”无效。收到自定义可写流

问题描述 投票:0回答:1

在 NodeJS 中,我希望能够捕获内存中生成进程的输出(无需写入文件,也不使用继承的 sysout)。

文档说我可以使用

Stream
...

对象:与子进程共享引用 tty、文件、套接字或管道的可读或可写流。流的底层文件描述符在子进程中复制到与 stdio 数组中的索引相对应的 fd。流必须有一个底层描述符(文件流在“打开”事件发生之前不会启动)。

...但是,当我传递自定义流时,我收到错误:

The argument 'stdio' is invalid. Received CustomWritableStream

我怀疑我需要一个底层描述符 - 但我不知道这意味着什么,或者如何实现它。

如何让我的捕获流正常工作? (这可能吗?)

代码片段:

class CustomWritableStream extends Writable {
  captureBuffer: string = '';
  _write(chunk: any, encoding: BufferEncoding, callback: (error?: Error | null) => void) {
    const chunkStr = chunk.toString();
    this.captureBuffer += chunkStr;
    callback();
  }
}

const stdout = new CustomWritableStream()
const stderr = new CustomWritableStream()
const child = child_process.spawn(cmd, { ...opts, stdio: ['ignore', stdout, stderr] })

类似:

node.js stream spawn
1个回答
0
投票

在 Node.js 中捕获生成进程的输出

如何使用 Node.js 捕获内存中生成进程的输出,而不写入文件或使用继承的 stdout。我们将介绍两种方法:使用自定义流和使用专用类来捕获流程输出。

目录

  1. 简介
  2. 理解底层描述符
  3. 方法 1:自定义流
  4. 方法 2:ProcessOutputCapture 类
  5. 结论

简介

在 Node.js 中使用子进程时,您可能需要在内存中捕获它们的输出(stdout 和 stderr)。这对于各种场景都很有用,例如运行命令行工具并以编程方式处理其输出。

理解底层描述符

在 Node.js 中,流是用于处理流数据的抽象接口。在处理子进程及其输出时,理解“底层描述符”的概念非常重要。

底层描述符是流用于读取或写入的低级 I/O 机制。对于文件流来说,这个描述符就是文件描述符。对于进程流(如 stdout 和 stderr),它是一个管道。

生成子进程时,Node.js 需要正确设置这些底层描述符以捕获输出。这就是为什么简单地将自定义流传递给

child_process.spawn()
并不能开箱即用——自定义流没有 Node.js 可以使用的底层描述符。

方法 1:自定义流

捕获输出的一种方法是创建将数据存储在内存中的自定义流。我们将实现两种类型的流:a

CustomWritableStream
CustomDuplexStream

自定义可写流

const { Writable } = require('stream');

class CustomWritableStream extends Writable {
  constructor(options) {
    super(options);
    this.captureBuffer = '';
  }

  _write(chunk, encoding, callback) {
    const chunkStr = chunk.toString();
    this.captureBuffer += chunkStr;
    callback();
  }

  getContents() {
    return this.captureBuffer;
  }
}

自定义双工流

const { Duplex } = require('stream');

class CustomDuplexStream extends Duplex {
  constructor(options) {
    super(options);
    this.captureBuffer = '';
  }

  _write(chunk, encoding, callback) {
    const chunkStr = chunk.toString();
    this.captureBuffer += chunkStr;
    callback();
  }

  _read(size) {
    // This method is required for Duplex streams, but we don't need to implement it
    // since we're not reading from this stream
  }

  getContents() {
    return this.captureBuffer;
  }
}

这些自定义流将传入数据存储在

captureBuffer
字符串中。
getContents()
方法允许您检索捕获的输出。

方法 2:ProcessOutputCapture 类

另一种方法是创建一个专用类来捕获流程输出。此类使用 Node.js 的内置流和事件来捕获输出。

const { spawn } = require('child_process');

class ProcessOutputCapture {
  constructor() {
    this.stdoutBuffer = '';
    this.stderrBuffer = '';
  }

  captureOutput(command, args = []) {
    return new Promise((resolve, reject) => {
      const child = spawn(command, args, { stdio: ['ignore', 'pipe', 'pipe'] });

      child.stdout.on('data', (data) => {
        this.stdoutBuffer += data.toString();
      });

      child.stderr.on('data', (data) => {
        this.stderrBuffer += data.toString();
      });

      child.on('close', (code) => {
        resolve({
          stdout: this.stdoutBuffer,
          stderr: this.stderrBuffer,
          exitCode: code
        });
      });

      child.on('error', (error) => {
        reject(error);
      });
    });
  }

  getStdout() {
    return this.stdoutBuffer;
  }

  getStderr() {
    return this.stderrBuffer;
  }

  clearBuffers() {
    this.stdoutBuffer = '';
    this.stderrBuffer = '';
  }
}

此类提供了捕获输出、分别检索 stdout 和 stderr 以及清除缓冲区的方法。

使用示例

const capture = new ProcessOutputCapture();
capture.captureOutput('ls', ['-l'])
  .then(result => {
    console.log('Stdout:', result.stdout);
    console.log('Stderr:', result.stderr);
    console.log('Exit code:', result.exitCode);
  })
  .catch(error => {
    console.error('Error:', error);
  });

结论

这两种方法都提供了使用 Node.js 捕获内存中生成进程的输出的有效方法。自定义流方法提供了更大的灵活性,可以在各种场景中使用,而

ProcessOutputCapture
类提供了更简单、更集中的解决方案来捕获流程输出。

选择最适合您的特定用例和编码风格的方法。请记住在实施中适当处理错误和边缘情况。

© www.soinside.com 2019 - 2024. All rights reserved.