首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >解析Node.js中的大型日志文件-逐行读取

解析Node.js中的大型日志文件-逐行读取
EN

Stack Overflow用户
提问于 2013-04-15 16:37:21
回答 12查看 114K关注 0票数 136

我需要对Javascript/Node.js (我使用的是Cube)中的大型(5-10 Gb)日志文件进行一些解析。

logline类似于:

10:00:43.343423 I'm a friendly log message. There are 5 cats, and 7 dogs. We are in state "SUCCESS".

我们需要读取每一行,执行一些解析(例如,剥离57SUCCESS),然后使用多维数据集的JS客户端将这些数据放入多维数据集(https://github.com/square/cube)。

首先,在Node中逐行读取文件的规范方法是什么?

这似乎是一个在网上相当常见的问题:

许多答案似乎指向了一堆第三方模块:

然而,这似乎是一个相当基本的任务-当然,在stdlib中有一种简单的方法来逐行读取文本文件?

其次,我需要处理每一行(例如,将时间戳转换为Date对象,并提取有用的字段)。

要做到这一点,最好的方法是最大化吞吐量?有没有什么方法既不会阻塞每一行的读取,也不会阻止将其发送到Cube?

第三-我猜是使用字符串拆分,以及contains的JS等效项(IndexOf != -1?)会比正则表达式快很多吗?有没有人有在Node.js中解析海量文本数据的丰富经验?

干杯,维克多

EN

回答 12

Stack Overflow用户

回答已采纳

发布于 2014-05-16 21:12:54

我寻找了一种使用流逐行解析超大文件(gbs)的解决方案。所有的第三方库和示例都不符合我的需要,因为它们不是逐行处理文件(如1、2、3、4.)或者将整个文件读取到内存中

下面的解决方案可以使用流和管道逐行解析非常大的文件。为了测试,我使用了一个2.1 gb的文件,其中包含17.000.000条记录。Ram使用量未超过60MB。

首先,安装event-stream包:

npm install event-stream

然后:

var fs = require('fs')
    , es = require('event-stream');

var lineNr = 0;

var s = fs.createReadStream('very-large-file.csv')
    .pipe(es.split())
    .pipe(es.mapSync(function(line){

        // pause the readstream
        s.pause();

        lineNr += 1;

        // process line here and call s.resume() when rdy
        // function below was for logging memory usage
        logMemoryUsage(lineNr);

        // resume the readstream, possibly from a callback
        s.resume();
    })
    .on('error', function(err){
        console.log('Error while reading file.', err);
    })
    .on('end', function(){
        console.log('Read entire file.')
    })
);

请让我知道它的进展如何!

票数 229
EN

Stack Overflow用户

发布于 2013-04-15 18:44:50

您可以使用内置的readline包,请参阅文档here。我使用stream创建一个新的输出流。

var fs = require('fs'),
    readline = require('readline'),
    stream = require('stream');

var instream = fs.createReadStream('/path/to/file');
var outstream = new stream;
outstream.readable = true;
outstream.writable = true;

var rl = readline.createInterface({
    input: instream,
    output: outstream,
    terminal: false
});

rl.on('line', function(line) {
    console.log(line);
    //Do your stuff ...
    //Then write to outstream
    rl.write(cubestuff);
});

处理大文件需要一些时间。一定要说出它是否有效。

票数 80
EN

Stack Overflow用户

发布于 2016-03-11 18:47:06

我真的很喜欢@gerard answer,实际上它应该是这里的正确答案。我做了一些改进:

HTTP是在一个类(modular)

  • Parsing is included

  • Ability to resume被提供给外部的,以防有一个异步作业被链接到读取CSV,比如插入到DB,或者用户可以声明的块/批大小的HTTPrequest

  • Reading。我也注意到了流中的编码,以防你有不同编码的文件。

代码如下:

'use strict'

const fs = require('fs'),
    util = require('util'),
    stream = require('stream'),
    es = require('event-stream'),
    parse = require("csv-parse"),
    iconv = require('iconv-lite');

class CSVReader {
  constructor(filename, batchSize, columns) {
    this.reader = fs.createReadStream(filename).pipe(iconv.decodeStream('utf8'))
    this.batchSize = batchSize || 1000
    this.lineNumber = 0
    this.data = []
    this.parseOptions = {delimiter: '\t', columns: true, escape: '/', relax: true}
  }

  read(callback) {
    this.reader
      .pipe(es.split())
      .pipe(es.mapSync(line => {
        ++this.lineNumber

        parse(line, this.parseOptions, (err, d) => {
          this.data.push(d[0])
        })

        if (this.lineNumber % this.batchSize === 0) {
          callback(this.data)
        }
      })
      .on('error', function(){
          console.log('Error while reading file.')
      })
      .on('end', function(){
          console.log('Read entirefile.')
      }))
  }

  continue () {
    this.data = []
    this.reader.resume()
  }
}

module.exports = CSVReader

因此,基本上,以下是您将如何使用它:

let reader = CSVReader('path_to_file.csv')
reader.read(() => reader.continue())

我用一个35 it的CSV文件测试了它,它对我很有效,这就是为什么我选择基于@gerard的答案来构建它,欢迎反馈。

票数 35
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16010915

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档