Node.js的child_process exec命令的标准输出被截断了

13

在 Node.js 中,我使用 child_process 模块的 exec 命令来调用一个Java算法,并将大量文本返回到标准输出,然后进行解析和使用。我基本上能够捕获它,但是当它超过一定数量的行数时,内容会被截断。

exec("sh target/bin/solver "+fields.dimx+" "+fields.dimy, function(error, stdout, stderr){
    //do stuff with stdout
}

我尝试过使用setTimeout和回调函数,但是没有成功,我觉得这是因为在代码中引用了stdout,但stdout尚未完全检索完成。我已经测试了stdout确实是数据丢失的第一个发生位置,不是在后面的异步问题。我还在本地机器和Heroku上测试过,每次都会在精确相同的行号处截断。

有什么想法或建议可以帮忙解决吗?


3个回答

10

我曾经尝试使用@damphat的方法,但是导致exec.stdout.on('end')的回调函数一直无法执行。

另一个解决方法是在exec的选项中增加缓冲区大小:请参阅文档here

{ encoding: 'utf8',
  timeout: 0,
  maxBuffer: 200*1024, //increase here
  killSignal: 'SIGTERM',
  cwd: null,
  env: null }

引用: maxBuffer指定允许在stdout或stderr上的最大数据量 - 如果超过此值,则会杀死子进程。现在我使用以下内容:与已接受的解决方案相比,这不需要处理由逗号分隔的块的分离部分。

exec('dir /b /O-D ^2014*', {
    maxBuffer: 2000 * 1024 //quick fix
    }, function(error, stdout, stderr) {
        list_of_filenames = stdout.split('\r\n'); //adapt to your line ending char
        console.log("Found %s files in the replay folder", list_of_filenames.length)
    }
);

9

这个问题的真正(也是最好的)解决方案是使用 spawn 而不是 exec。如 本文 所述,spawn 更适合处理大量数据:

child_process.exec 返回来自子进程的整个缓冲区输出。默认情况下,缓冲区大小设置为 200k。如果子进程返回的内容超过了这个大小,你的程序将崩溃并显示错误消息“Error:maxBuffer exceeded”。你可以通过在 exec 选项中设置更大的缓冲区大小来解决这个问题。但你不应该这样做,因为 exec 不适用于返回巨大缓冲区给 Node 的进程。你应该使用 spawn 来处理这种情况。那么你要用 exec 做什么?用它来运行返回结果状态而不是数据的程序。

与 exec 不同,spawn 需要不同的语法:

var proc = spawn('sh', ['target/bin/solver', 'fields.dimx', 'fields.dimy']);

proc.on("exit", function(exitCode) {
    console.log('process exited with code ' + exitCode);
});

proc.stdout.on("data", function(chunk) {
    console.log('received chunk ' + chunk);
});

proc.stdout.on("end", function() {
    console.log("finished collecting data chunks from stdout");
});

1
谢谢您的答复!它帮助我了解到我的 exec 由于1MB的输出而返回了一个错误。不幸的是,exec 的错误对象只返回命令名称,而没有详细说明错误的原因:{"cmd":"./read_mail.sh"} - ishahak

4

编辑: 我在我的电脑(windows)上尝试了 dir /s 并遇到了相同的问题(看起来像是一个bug),这段代码解决了我的问题:

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

function my_exec(command, callback) {
    var proc = exec(command);

    var list = [];
    proc.stdout.setEncoding('utf8');

    proc.stdout.on('data', function (chunk) {
        list.push(chunk);
    });

    proc.stdout.on('end', function () {
        callback(list.join());
    });
}

my_exec('dir /s', function (stdout) {
    console.log(stdout);
})

你为什么认为它看起来像一个 bug?请看一下我的回答。 - olamotte
@olamotte,你可以查看这个答案的历史记录,我已经增加了缓冲区大小,但对我没有起作用。 - damphat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接