Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/36.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 在节点中高效地逐行读取文件_Javascript_Node.js - Fatal编程技术网

Javascript 在节点中高效地逐行读取文件

Javascript 在节点中高效地逐行读取文件,javascript,node.js,Javascript,Node.js,我已经学会了用它逐行读取文件,例如 readline .createInterface({input: fs.createReadStream('xxx')}) .on('line', (line) => { apply_regexp_on_line }) .on('close', () => { report_all_regexps }); 但是,这相当慢,因为我比较了grep和JavaScript regexp的性能,后者在我测试的regexp上有更好的

我已经学会了用它逐行读取文件,例如

readline
    .createInterface({input: fs.createReadStream('xxx')})
    .on('line', (line) => { apply_regexp_on_line })
    .on('close', () => { report_all_regexps });
但是,这相当慢,因为我比较了
grep
和JavaScript regexp的性能,后者在我测试的regexp上有更好的性能。(请参阅)因此,我认为我必须归咎于节点异步读取线

在我的情况下,我根本不关心异步,我只需要利用JavaScript中的快速regexp来处理非常大的日志文件(通常为1-2GB,有时高达10GB)。这样做的最佳方式是什么?我唯一关心的是速度


优点:一些日志文件是gzip文件,所以我需要解压缩它们。如果有人能为我推荐一款快速逐行阅读纯文本和压缩文本的阅读器,我将不胜感激。

这与您的数据相比如何

// module linegrep.js
'use strict';
var through2 = require('through2');
var StringDecoder = require('string_decoder').StringDecoder

function grep(regex) {
    var decoder = new StringDecoder('utf8'),
        last = "",
        lineEnd = /\r?\n/;

    var stream = through2({}, function transform(chunk, enc, cb) {
        var lines = decoder.write(last + chunk).split(lineEnd), i;
        last = lines.pop();
        for (i = 0; i < lines.length; i++) {
            if (regex.test(lines[i])) this.push(lines[i]);
        }
        cb();
    }, function flush(cb) {
        if (regex.test(last)) this.push(last);
        cb();
    });
    stream._readableState.objectMode = true;
    return stream;
}

module.exports = grep;

这会将文件流转换为行的对象流,通过正则表达式映射它们,并仅返回匹配的行。

不确定在行上应用正则表达式做什么,但是否可以使用unix
sed
程序替换字符串?很快。可能可以编写一个快速简单的shell脚本来进行解压缩和sed'ing。请参阅问题中的基准测试链接
sed
不如JavaScript快。基本上,
apply_regexp_on_line
将使用regexp捕获日志文件中的一些文本并存储它,
report_all_regexp
将以给定的格式报告捕获的文本。@xis您确定没有在基准测试中计时新进程的分叉吗<如果您考虑到必须读取文件并生成输出,那么code>sed和
grep
将比JS快得多。如果您的JS测试没有对I/O部分计时(看起来好像没有:它会将数据读入内存并根据该部分运行基准测试),那么几乎不可能进行公平的比较。@VsevolodGoloviznin我只是这样做了,但日志文件的大小较小,只有128MB,因为我的基准测试代码使用的是JavaScript缓冲区,限制为192MB。grep耗时0.41秒,node耗时0.32秒。我用
/usr/bin/time
而不是我的代码来计算时间。我的regexp是
boot\([a-z]+)\u head\。
,两者都有57654个捕获。@SamuelToh请查看Tomalak的答案。至少我们现在对grep的性能是一样的。忘记提到基准数据:grep花了约1.2秒,而grep花了0.42秒,toString代码用了0.32秒。这要快得多,对egrep的性能是一样的,都是3.1秒(我使用的是另一个文件/计算机,所以结果可能不同)。好吧,基本上你没有错。通过将第一种方法中的多个管道(拆分->映射->过滤器)融合到一个管道中,我确实删除了相当多的事件传递。我还重写了split代码(最初来自split2npm模块),在这个过程中对其进行了一些优化。我猜上面代码中的
last
处理仍然有一点效率低下,如果你想让它变得更智能,也许它可以帮助你再获得几毫秒。@xis-Oh,并且不解码输入,因为utf8也有影响。如果日志文件使用单字节编码,请相应地配置代码。当然,如果您在此处做出错误的假设,您可能会损坏数据。将/\r?\n/替换为“\n”将进一步提高性能,仅供参考。我确信我正在使用UNIX newline。
// index.js

'use strict';
var fs = require('fs');
var zlib = require('zlib');
var grep = require('./linegrep');

function grepFile(filename, regex) {
    var rstream = fs.createReadStream(filename, {highWaterMark: 172 * 1024});
    if (/\.gz$/.test(filename)) rstream = rstream.pipe(zlib.createGunzip());
    return rstream
        .pipe(grep(regex));
}

// -------------------------------------------------------------------------

var t = Date.now(), mc = 0;
grepFile('input.txt', /boot\.([a-z]+)_head\./).on('data', function (line) {
    mc++;
    console.log(line);
}).on('end', function () {
    console.log( mc + " matches, " + (Date.now() - t) + " ms" );
});