ITKeyword,专注技术干货聚合推荐

注册 | 登录

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

qqHJQS 分享于 2016-06-29

2018阿里云全部产品优惠券(新购或升级都可以使用,强烈推荐)
领取地址https://promotion.aliyun.com/ntms/act/ambassador/sharetouser.html?userCode=gh9qh5ki&utm_source=gh9qh5ki

现在有个需求是这样:
“某个应用会产生日志文件,使用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有点让我抓狂了,我开始喜欢上它了~~~

现在有个需求是这样: “某个应用会产生日志文件,使用nodejs开发程序完成对日志的操作:当程序启动的时候首先获取日志所有内容并作相关处理,然后对日志监控,如果有新的内容添加进来,立即获
在线网页数据采集器

相关阅读排行


用户评论

游客

相关内容推荐

  • 1
  • 2
  • 3
  • 4
  • 苹果6背夹充电宝超薄

最新文章

×

×

请激活账号

为了能正常使用评论、编辑功能及以后陆续为用户提供的其他产品,请激活账号。

您的注册邮箱: 修改

重新发送激活邮件 进入我的邮箱

如果您没有收到激活邮件,请注意检查垃圾箱。