一、node文件读写
Node.js读取文件函数语法如下:
1. 异步读文件
fs.readFile(filename,[encoding],[callback(err,data)])
- filename(必选),表示要读取的文件名。
- encoding(可选),表示文件的字符编码。
- callback 是回调函数,用于接收文件的内容。
示例:
var fs=require('fs');
fs.readFile('./data/result.txt', 'utf-8', function (err, stdout) {
if (err) {
console.log('文件读取失败');
} else {
console.log('文件读取成功');
res.render('index', {
input: description,
content: stdout,
})
console.log('stdout:', stdout);
stdout = '';
}
});
PS:read和readFile比较
read是不断地将文件中的一小块内容读入缓存区,最后从该缓存区中读取文件内容,
而readFile则是将文件一次性读取完毕,如果文件较大,则会出现"爆仓"。
2.异步写文件
fs.writeFile(filename,data,[options],callback)
- filename:要写入的文件
- data:写入文件的数据可以是字符串,可以是buffer
- options:flag:对写入文件的操作默认为w,encoding:编码,mode:权限
- callback:回调函数
以下介绍下常见的文件的操作 flag, 详细文件操作区别请看这篇文章
♥ flag: w -- 新建只写(以 w 方式打开,不能读出,w+ 可读写)
a -- 附加写方式 (a:附加写方式打开,不可读;a+: 附加读写方式打开)
♥ 如果文件不存在会创建新文件的打开方式:a,a+,w,w+,而 r 和 U 要求文件必须存在
示例:
// 引入fs
var fs = require("fs");
// 获取用户提交的内容
var description = req.body.description;
// 写入文件
fs.writeFile('./data/text.txt', description, {
flag: 'w',
encoding: 'utf-8',
mode: '0666'
}, function (err) {
if (err) {
console.log("文件写入失败")
} else {
console.log("文件写入成功");
}
});
3.同步读写文件
var date = fs.readFileSync('log.txt','utf-8');
fs.writeFileSync('output.txt', JSON.stringify(obj, null, '\t'));
4.同步与异步读写的区别
♥ 同步会阻塞,阻塞时,代码不能做其它的事情,需要等待当前代码执行完毕, 而异步则无需等待当前代码执行完毕。
二、node执行python文件
1. child_process介绍
Node.js 是以单线程的模式运行的,但它使用的是事件驱动来处理并发。这样有助于我们在多核 cpu 的系统上创建多个子进程,并使用主进程和子进程之间实现通信,从而提高性能。
每个子进程总是带有三个流对象:child.stdin, child.stdout 和child.stderr。他们可能会共享父进程的 stdio 流,或者也可以是独立的被导流的流对象。
Node
提供了child_process
模块来创建子进程。
2. 创建子进程方法
-
exec-child_process.exec
使用子进程执行命令,缓存子进程的输出,并将子进程的输出以回调函数的形式返回。
示例:
var child_process = require('child_process');
var workerProcess = child_process.exec('python3 test.py '+i, function (error, stdout, stderr) {
if (error) {
console.log(error.stack);
console.log('Error code: '+error.code);
console.log('Signal received: '+error.signal);
}
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
});
workerProcess.on('exit', function (code) {
console.log('子进程已退出,退出码 '+code);
});
-
spawn-child_process.spawn
使用指定的命令行参数创建进程。
示例:
var child_process = require('child_process');
var workerProcess = child_process.spawn('python3', ['test.py']);
workerProcess.stdout.on('data', function (data) {
console.log('stdout: ' + data);
});
workerProcess.stderr.on('data', function (data) {
console.log('stderr: ' + data);
});
workerProcess.on('close', function (code) {
console.log('子进程已退出,退出码 ' + code);
});
-
fork-child_process.fork
是spawn()的特殊形式,用于在子进程中运行模块,与spawn方法不同的是,fork会在父进程与子进程之间,建立一个通信管道,用于进程之间的通信。
暂无示例
3. 比较exec和spawn
- exec将子进程输出结果暂放在buffer中,在结果完全返回后,再将输出一次性的以回调函数返回。如果exec的buffer体积设置的不够大,它将会以一个“maxBuffer exceeded”错误失败告终。而spawn在子进程开始执行后,就不断的将数据从子进程返回给主进程,它没有回调函数,它通过流的方式发数据传给主进程,从而实现了多进程之间的数据交换。
- 书写上,exec更方便一些,将整个命令放在第一个参数中,而spqwn需要拆分。
child_process.spawn('python3', ['test.py', i])
child_process.exec('python3 test.py '+i, callback)
- exec比spawn多了一些默认的option
4.解决 Error: maxBuffer exceeded
问题描述:
在使用子进程期间遇到了问题 Error: stderr maxBuffer exceeded ,然后 子进程挂掉。
原因:
让我们从源码上解释子进程为什么子进程会挂掉?
child.stderr.addListener('data', function(chunk) {
stderrLen += chunk.length;
if (stderrLen > options.maxBuffer) {
ex = new Error('stderr maxBuffer exceeded.');
kill();
} else {
if (!encoding)
_stderr.push(chunk);
else
_stderr += chunk;
}
});
以上代码逻辑:
记录子进程的log大小,一旦超过maxBuffer
就kill
掉子进程。
而当我们在使用exec
时,不知道设置maxBuffer
,默认的maxBuffer
是200K,当我们子进程日志达到200K时,自动kill()
掉了。
// exec 默认的参数
var options = {
encoding: 'utf8',
timeout: 0,
maxBuffer: 200 * 1024,
killSignal: 'SIGTERM',
cwd: null,
env: null
};
解决方案
知道上面原因了,解决方案就有几个了:
- 子进程的系统,不再输出日志
- maxBuffer这个传一个足够大的参数
- 直接使用spawn,放弃使用exec
我这里采用的是第三种直接使用spawn
,解除maxBuffer
的限制,个人觉得最优的方案。因为exec本身就是
结束