使用Node.js实时读取文件

Oli*_*oyd 12 javascript real-time fifo unix-socket node.js

我需要使用node.js实时读出正在写入文件的数据的最佳方法.麻烦的是,Node是一艘快速发展的船,它使寻找解决问题的最佳方法变得困难.

我想做什么
我有一个正在做某事的java进程,然后把它做的事情的结果写到文本文件中.它通常需要5分钟到5个小时才能运行,数据写入的时间很长,并且可以达到一些相当高的吞吐率(大约1000线/秒).

我想实时读取这个文件,然后使用节点聚合数据并将其写入套接字,在套接字上可以在客户端上绘制图形.

客户端,图形,套接字和聚合逻辑都已完成,但我对阅读文件的最佳方法感到困惑.

我尝试过(或者至少玩过)
FIFO - 我可以告诉我的Java进程写一个fifo并使用node读取它,这实际上是我们如何使用Perl实现这个目的,但是因为其他一切都在节点中运行将代码移植过来是有意义的.

Unix Sockets - 如上.

fs.watchFile - 这会对我们需要的东西起作用吗?

fs.createReadStream - 这比watchFile好吗?

fs&tail -f- 似乎是一个黑客.

实际上,我的问题是什么,
我倾向于使用Unix套接字,这似乎是最快的选择.但节点是否具有更好的内置功能,可以实时读取fs中的文件?

has*_*sin 9

如果您希望将文件保留为数据的持久存储,以防止在系统崩溃或网络中正在运行的进程中的某个成员死亡时丢失流,您仍然可以继续写入文件并阅读从中.

如果您不需要将此文件作为Java进程生成结果的持久存储,那么使用Unix套接字对于简易性和性能都要好得多.

fs.watchFile() 不是你需要的,因为它适用于文件统计信息,因为文件系统报告它,并且因为你想要读取已经写入的文件,所以这不是你想要的.

简短更新:我很遗憾地意识到虽然我fs.watchFile()在前一段中被指控使用文件统计数据,但我在下面的示例代码中自己做了同样的事情!虽然我已经警告读者"要小心!" 因为我在几分钟内写完了它,甚至没有测试好; 仍然,通过使用fs.watch()而不是watchFilefstatSync如果底层系统支持它,它可以做得更好.

对于从文件中读取/写入,我在下面的内容中写了以下内容以获得乐趣:

test-fs-writer.js:[因为你在Java进程中编写文件所以不需要这个]

var fs = require('fs'),
    lineno=0;

var stream = fs.createWriteStream('test-read-write.txt', {flags:'a'});

stream.on('open', function() {
    console.log('Stream opened, will start writing in 2 secs');
    setInterval(function() { stream.write((++lineno)+' oi!\n'); }, 2000);
});
Run Code Online (Sandbox Code Playgroud)

test-fs-reader.js:[注意,这只是演示,检查错误的对象!]

var fs = require('fs'),
    bite_size = 256,
    readbytes = 0,
    file;

fs.open('test-read-write.txt', 'r', function(err, fd) { file = fd; readsome(); });

function readsome() {
    var stats = fs.fstatSync(file); // yes sometimes async does not make sense!
    if(stats.size<readbytes+1) {
        console.log('Hehe I am much faster than your writer..! I will sleep for a while, I deserve it!');
        setTimeout(readsome, 3000);
    }
    else {
        fs.read(file, new Buffer(bite_size), 0, bite_size, readbytes, processsome);
    }
}

function processsome(err, bytecount, buff) {
    console.log('Read', bytecount, 'and will process it now.');

    // Here we will process our incoming data:
        // Do whatever you need. Just be careful about not using beyond the bytecount in buff.
        console.log(buff.toString('utf-8', 0, bytecount));

    // So we continue reading from where we left:
    readbytes+=bytecount;
    process.nextTick(readsome);
}
Run Code Online (Sandbox Code Playgroud)

您可以安全地避免使用nextTickreadsome()直接调用.由于我们仍然在这里工作同步,因此在任何意义上都没有必要.我喜欢它.:p

Oliver Lloyd编辑

以上面的例子,但扩展它来读取CSV数据给出:

var lastLineFeed,
    lineArray;
function processsome(err, bytecount, buff) {
    lastLineFeed = buff.toString('utf-8', 0, bytecount).lastIndexOf('\n');

    if(lastLineFeed > -1){

        // Split the buffer by line
        lineArray = buff.toString('utf-8', 0, bytecount).slice(0,lastLineFeed).split('\n');

        // Then split each line by comma
        for(i=0;i<lineArray.length;i++){
            // Add read rows to an array for use elsewhere
            valueArray.push(lineArray[i].split(','));
        }   

        // Set a new position to read from
        readbytes+=lastLineFeed+1;
    } else {
        // No complete lines were read
        readbytes+=bytecount;
    }
    process.nextTick(readFile);
}
Run Code Online (Sandbox Code Playgroud)


vik*_*vik 7

为什么你认为tail -f是黑客?

虽然弄清楚我找到了一个很好的例子,但我会做类似的事情.node.js和WebSocket的实时在线活动监控示例:http:
//blog.new-bamboo.co.uk/2009/12/7/real-time-online-activity-monitor-example-with-node-js -and-的WebSocket

只是为了让这个答案完整,我给你写了一个在0.8.0下运行的示例代码 - (http服务器可能是一个黑客).

生成子进程是使用tail运行的,因为子进程是一个带有三个流的EventEmitter(在我们的例子中我们使用stdout),你可以添加一个监听器 on

filename:tailServer.js

用法: node tailServer /var/log/filename.log

var http = require("http");
var filename = process.argv[2];


if (!filename)
    return console.log("Usage: node tailServer filename");

var spawn = require('child_process').spawn;
var tail = spawn('tail', ['-f', filename]);

http.createServer(function (request, response) {
    console.log('request starting...');

    response.writeHead(200, {'Content-Type': 'text/plain' });

    tail.stdout.on('data', function (data) {
      response.write('' + data);                
    });
}).listen(8088);

console.log('Server running at http://127.0.0.1:8088/');
Run Code Online (Sandbox Code Playgroud)