前几天以前写的一段程序忽然报了个诡异的异常"maxBuffer exceeded",追进去发现是在一个上传的模块中解压缩的时候调用了child_process.exec方法,在解压某个上传文件的时候抛异常了。而解压其余的文件就没有问题。因而把这个文件找出来,单独写了个如出一辙的exec,调个子进程解压缩一遍,发现也没有错误,问题是一旦放到以前那段程序里面就报错了。因而只能去查API了。node
在nodejs的child_process模块中,有两个相似的方法spawn和exec,都是经过生成一个子进程,去执行指定的命令,不过他们的用法稍有不一样,在命令的指定上,exec相对灵活,等于一个shell的命令行,如'ps -ef | grep node'此类的管道操做也能一次性实现。
nodejs文档用法e.x:shell
var cp = require('child_process'); //spawn var ls = cp.spawn('ls'/*command*/, ['-lh', '/usr']/*args*/, {}/*options, [optional]*/); ls.stdout.on('data', function (data) { console.log('stdout: ' + data); }); ls.stderr.on('data', function (data) { console.log('stderr: ' + data); }); ls.on('exit', function (code) { console.log('child process exited with code ' + code); }); //exec cp.exec('ls -lh /usr'/*command*/,{}/*options, [optiona]l*/, function(err, stdout, stderr){ console.log('stdout: ' + stdout); console.log('stderr: ' + stderr); })
这时忽然发现了一个一直被我忽略了的参数options,用来设定子进程的环境和执行条件。
spawn的options默认为:函数
{ cwd: undefined, env: process.env, setsid: false }
exec的options默认为:ui
{ encoding: 'utf8', timeout: 0, /*子进程最长执行时间 */ maxBuffer: 200*1024, /*stdout和stderr的最大长度*/ killSignal: 'SIGTERM', cwd: null, env: null }
在exec的options中有一个选项maxBuffer,看到这就清楚了,估计是超出了这个maxBuffer。果真,回到刚才单独写的解压程序里面,把maxBuffer设为一个较小的值,就出现这个错误了。exec的默认stdout最大大小为200K,刚才写的这个程序由于PWD跟以前的代码不一样,所以stdout变小了,致使问题没有重现。把子进程中解压文件的命令改为静默模式,就能够暂时把这个问题解决了。固然,也能够将其改写成spawn来完成,就不会有maxBuffer的限制了。spa
虽然在上面的文档用法中,spwan和exec的最终回调方式有区别,可是在node的实现中,其实二者的实现方式是一致的,exec也能够像spawn同样使用,只不过exec在触发stderr和stdout的data事件的时候,会把数据写到字符串中,到执行结束或者错误退出的时候经过回调函数传递出来,实现了exec这种便捷用法。pwa
var cp = require('child_process'); //exec能够像spawn同样使用 var ls = cp.exec('ls -lh /usr', {}/*options, [optional]*/); ls.stdout.on('data', function (data) { console.log('stdout: ' + data); }); ls.stderr.on('data', function (data) { console.log('stderr: ' + data); }); ls.on('exit', function (code) { console.log('child process exited with code ' + code); });
能够看出,exec在使用的便捷性上要超过spawn,且执行速度上也相差无几。不过这种便携性是要付出必定代价的。在exec的options中,有一项是maxBuffer,若是执行的command输出超出了这个长度,无论是采用回调函数方式,仍是emit data事件方式传递结果,都会抛出maxBuffer exceeded异常,而且杀死子进程。此时子进程可能已经执行完成(maxBuffer和须要长度相差不大,在收到最后一个数据包的时候才超出),也多是只执行了一半。所以若是须要使用exec,就要慎重设置maxBuffer(和timeout),或者对执行的命令采用静默方式(同时能够略微提高执行速度)。
ps:感受nodejs能够提供一个方法,把exec的回调函数传递结果(maxBuffer限制)去掉,保留exec的参数传递方式,就方便我这种小白了..命令行