Nodejs监控文件内容变化并获取最新添加的内容

来源:互联网 发布:尔湾安全知乎 编辑:程序博客网 时间:2024/05/18 13:27

现在有个需求是这样:
“某个应用会产生日志文件,使用nodejs开发程序完成对日志的操作:当程序启动的时候首先获取日志所有内容并作相关处理,然后对日志监控,如果有新的内容添加进来,立即获取到最新内容继续做处理”。当然,这里我把需求简化了,主要就是下面酱紫:
这里写图片描述
接触nodejs不到8小时,只有从nodejs的中文api找切入点,分别找到了两个模块
fs、ReadLine
watch和watchFile实现文件的监听,代码如下(watch):

var fs = require('fs');// 引入fs 模块var filePath = 'input.txt';fs.watch(filePath, function (event, filename) {      console.log('event is: ' + event);      if (filename) {         console.log('filename provided: ' + filename);        //readTxt();      } else {        console.log('filename not provided');      }  }});console.log(filePath + ' 被监听中...');

效果图如下:
这里写图片描述
只要是文件被修改后保存,程序会立即检测到(这里我有个疑问,我修改文件保存后,为什么会打印两遍?)
ReadLine的功能就是按行读取文件,相关代码如下:

var fs = require('fs');var readline = require('readline');// 引入readline模块var filename = 'input.txt';var rl = readline.createInterface({  input: fs.createReadStream(filename,{      enconding:'utf8'  }),  output: null});rl.on('line', function(line) {  if (line) {    console.log(line.toString());  }}).on('close', function() {  console.log('读文件结束!');});

对于没有用过nodejs但想学nodejs的人来说,我建议先把菜鸟学校里的教程看一遍,我接触nodejs的当天晚上就把上面的教程过了一遍。这样再深入的话会很快。跑题了。。。
上面代码的结果如图:
这里写图片描述
有了这两段代码,我很快有了方案

  • 程序开始使用readline将原有内容逐行读取并处理;
  • 处理完后使用watch监听文件;
  • 文件变动再次使用readline读文件内容,依次放在一个数组里,然后获取最后一个;

然而并非我想象的那样,如果一次插入多条内容,那我这个方案就不行了。
我想找有关file的第三方库,然而并没有我想要的,还是要自己写!
最后发现了watch里有个回调函数

fs.watchFile('input.text', function (curr, prev) {  console.log('the current mtime is: ' + curr.mtime);  console.log('the previous mtime was: ' + prev.mtime);});

请注意这两个参数curr,prev,我试着把curr的内容打印出来,如下:

{ dev: 997878,  mode: 33206,  nlink: 1,  uid: 0,  gid: 0,  rdev: 0,  blksize: undefined,  ino: 844424930190818,  size: 175,  blocks: undefined,  atime: Tue Jun 28 2016 20:36:43 GMT+0800 (中国标准时间),  mtime: Tue Jun 28 2016 22:53:46 GMT+0800 (中国标准时间),  ctime: Tue Jun 28 2016 22:53:46 GMT+0800 (中国标准时间),  birthtime: Mon Jun 27 2016 20:36:56 GMT+0800 (中国标准时间) }

我注意到里面有个size,这难道是文件的字节数?答案是的,那这样问题就解决了,新的方案出来了:

  • 使用readline先逐行获取内容并解析
  • 使用watchfile监控文件,当文件有内容添加使用curr和prev里的size来读取添加的内容
  • 得到新的内容,通过’\n\r’或’\n’将其截取成数组,这样就得到了一行一行的内容

这里需要用到fs的open和read

fs.open(path, flags, [mode], callback)fs.read(fd, buffer, offset, length, position, callback)

两个方法真的是绝配啊~~~看看中文api,很详细,配合的代码如下:

fs.open(filePath,'a+',function(error,fd){    var buffer;    var remainder = null;    fs.watchFile(filePath,{       persistent: true,       interval: 1000    },function(curr, prev){      //console.log(curr);        if(curr.mtime>prev.mtime){           //文件内容有变化,那么通知相应的进程可以执行相关操作。例如读物文件写入数据库等          buffer = new Buffer(curr.size - prev.size);// 创建一个缓冲,长度为(当前文件大小-文件上一个状态的大小)          fs.read(fd,buffer,0,(curr.size - prev.size),prev.size,function(err, bytesRead, buffer){            console.log(buffer.toString());//新增加的内容          });        }else{           console.log('文件读取错误');        }       });});

每次文件改动(这里主要指文件有新的内容追加上,没有考虑删除修改等情况),就将上一状态的大小作为本次读文件的起始位置
position—>prev.size
offset—>0 //在新建buffer的其实位置开始写入
length—>(curr.size - prev.size)
完整的代码如下:

var fs = require('fs');var readline = require('readline');var filename = 'input.txt';var logsArr = new Array();var listenArr = new Array();function init(){ sendHisLogs(filename, listenLogs);}function sendHisLogs(filename,listenLogs){  var rl = readline.createInterface({    input: fs.createReadStream(filename,{        enconding:'utf8'    }),    output: null,    terminal: false  //这个参数很重要  });  rl.on('line', function(line) {    if (line) {      logsArr.push(line.toString());    }  }).on('close', function() {    for(var i = 0 ;i<logsArr.length;i++){      console.log('发送历史信号: ' + logsArr[i]);      //generateLog(logsArr[i])    }    listenLogs(filename);  });}function generateLog(str){  var regExp = /(\[.+?\])/g;//(\\[.+?\\])  var res = str.match(regExp);  console.log(res);  for(i=0;i<res.length;i++){    res[i] = res[i].replace('[','').replace(']',''); //发送历史日志  }}var listenLogs = function(filePath){  console.log('日志监听中...');  var fileOPFlag="a+";  fs.open(filePath,fileOPFlag,function(error,fd){      var buffer;      var remainder = null;      fs.watchFile(filePath,{         persistent: true,         interval: 1000      },function(curr, prev){        console.log(curr);          if(curr.mtime>prev.mtime){             //文件内容有变化,那么通知相应的进程可以执行相关操作。例如读物文件写入数据库等            buffer = new Buffer(curr.size - prev.size);            fs.read(fd,buffer,0,(curr.size - prev.size),prev.size,function(err, bytesRead, buffer){              generateTxt(buffer.toString())            });          }else{             console.log('文件读取错误');          }         });         function generateTxt(str){ // 处理新增内容的地方          var temp = str.split('\r\n');          for(var s in temp){            console.log(temp[s]);          }         }  });}function getNewLog(path){  console.log('做一些解析操作');}init();

运行结果如下:
这里写图片描述

代码我先上传到这里

我这样写只是完成了我当前的需求,在接下来学习nodejs的过程中,我会对其进行优化,最后能将其打包上传到npm上!

nodejs有点让我抓狂了,我开始喜欢上它了~~~

0 0