我需要对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".
我们需要读取每一行,执行一些解析(例如,剥离5
、7
和SUCCESS
),然后使用多维数据集的JS客户端将这些数据放入多维数据集(https://github.com/square/cube)。
首先,在Node中逐行读取文件的规范方法是什么?
这似乎是一个在网上相当常见的问题:
许多答案似乎指向了一堆第三方模块:
然而,这似乎是一个相当基本的任务-当然,在stdlib中有一种简单的方法来逐行读取文本文件?
其次,我需要处理每一行(例如,将时间戳转换为Date对象,并提取有用的字段)。
要做到这一点,最好的方法是最大化吞吐量?有没有什么方法既不会阻塞每一行的读取,也不会阻止将其发送到Cube?
第三-我猜是使用字符串拆分,以及contains的JS等效项(IndexOf != -1?)会比正则表达式快很多吗?有没有人有在Node.js中解析海量文本数据的丰富经验?
干杯,维克多
发布于 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.')
})
);
请让我知道它的进展如何!
发布于 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);
});
处理大文件需要一些时间。一定要说出它是否有效。
发布于 2016-03-11 18:47:06
我真的很喜欢@gerard answer,实际上它应该是这里的正确答案。我做了一些改进:
HTTP是在一个类(modular)
代码如下:
'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的答案来构建它,欢迎反馈。
https://stackoverflow.com/questions/16010915
复制相似问题