使用节点child_process的stdout缓冲区问题

Yon*_*led 83 javascript node.js

我正在尝试使用节点child_process执行curl以从本地网络中的共享文件夹获取JSON文件(大约220Ko).但它实际上返回了一个我无法解决的缓冲问题.这是我的代码:

var exec = require('child_process').exec;

var execute = function(command, callback){
    exec(command, function(error, stdout, stderr){ callback(error, stdout); });
};

execute("curl http://" + ip + "/file.json", function(err, json, outerr) {
    if(err) throw err;
    console.log(json);
})
Run Code Online (Sandbox Code Playgroud)

这是我得到的错误:

if(err) throw err;
          ^
Error: stdout maxBuffer exceeded.
    at Socket.<anonymous> (child_process.js:678:13)
    at Socket.EventEmitter.emit (events.js:95:17)
    at Socket.<anonymous> (_stream_readable.js:746:14)
    at Socket.EventEmitter.emit (events.js:92:17)
    at emitReadable_ (_stream_readable.js:408:10)
    at emitReadable (_stream_readable.js:404:5)
    at readableAddChunk (_stream_readable.js:165:9)
    at Socket.Readable.push (_stream_readable.js:127:10)
    at Pipe.onread (net.js:526:21)
Run Code Online (Sandbox Code Playgroud)

Tim*_*per 149

您需要在使用时使用并设置maxBuffer选项child_process.exec.从文档:

maxBuffer 指定stdout或stderr上允许的最大数据量 - 如果超过此值,则子进程将被终止.

该文档还指出默认值为maxBuffer200KB.

例如,在以下代码中,最大缓冲区大小增加到500KB:

var execute = function(command, callback){
    exec(command, {maxBuffer: 1024 * 500}, function(error, stdout, stderr){ callback(error, stdout); });
};
Run Code Online (Sandbox Code Playgroud)

此外,您可能希望了解http.get它是否能够实现您的目标.

  • 现在默认值为 1MB @jlh,https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback (5认同)
  • 一个小技巧。如果设置“{maxBuffer: undefined}”,则缓冲区大小将没有限制。在命令生成输出时,“child_process”在内部分配小缓冲区块,因此它不会预先分配“maxBuffer”大小的缓冲区,而是根据需要增长它。“maxBuffer”仅作为故障安全装置来停止输出过多的进程。`undefined` 恰好溜过了验证检查,并且还绕过了故障保护。它没有在任何地方记录,并且可能随时停止工作。小心使用。 (4认同)
  • 这个默认值小得离谱。这是我第二次被这个难找的东西咬了。 (2认同)

小智 49

我有一个类似的问题,我修复它从exec移动到spawn:

var child = process.spawn('<process>', [<arg1>, <arg2>]);

child.stdout.on('data', function (data) {
  console.log('stdout: ' + data);
});

child.stderr.on('data', function (data) {
  console.log('stderr: ' + data);
});

child.on('close', function (code) {
    console.log('child process exited with code ' + code);
});
Run Code Online (Sandbox Code Playgroud)

  • 这似乎是[最合适的](http://www.hacksparrow.com/difference-between-spawn-and-exec-of-node-js-child_process.html)两者的解决方案 (10认同)
  • 这个答案不一定是最合适的。我认为问题中的控制台输出可能只是一个例子。几乎没有人会获取 200KB 的文件并将其扔到控制台。然而,如果 `process.exec` 用于 CLI 工具之类的东西,那么切换到 `spawn` 应该是正确的选择。 (3认同)
  • 哇……产卵很酷。它甚至不使用回调或承诺......只是事件。这对于将标准输出流式传输到控制台非常有用。@Pavel Gatilov,这正是我们正在做的事情。FFMpeg 喜欢每秒显示进度...这会对缓冲区造成影响 (2认同)

RAX*_*RAX 9

对答案添加一些解释。

exec 命令在将数据发送到父进程之前缓冲数据。它通常适用于产生较小输出的命令。发生上述错误是因为执行命令生成的输出大于最大缓冲区大小。解决上述问题的一种方法是指定缓冲区大小,如 Tim Cooper 所回答。

var execute = function(command, callback){
exec(command, {maxBuffer: 1024 * 500}, function(error, stdout, stderr){ 
 callback(error, stdout); });
};
Run Code Online (Sandbox Code Playgroud)

另一种解决方案是使用 spawn 方法,该方法通常比 exec 更快,并且在发送之前不会缓冲数据。它以流的形式发送数据,因此永远不会出现缓冲区大小的问题。Isampaio 使用的代码片段。

var child = process.spawn('<process>', [<arg1>, <arg2>]);
child.stdout.on('data', function (data) {
 console.log('stdout: ' + data);
});
child.stderr.on('data', function (data) {
 console.log('stderr: ' + data);
});
child.on('close', function (code) {
 console.log('child process exited with code ' + code);
});
Run Code Online (Sandbox Code Playgroud)