我需要使用node.js实时读出正在写入文件的数据的最佳方法.麻烦的是,Node是一艘快速发展的船,它使寻找解决问题的最佳方法变得困难.
我想做的事
我有一个正在做某事的java进程,然后将它所做的事情的结果写入文本文件.它通常需要5分钟到5个小时才能运行,数据写入的时间很长,并且可以达到一些相当高的吞吐率(大约1000行/秒).
我想实时读取这个文件,然后使用节点聚合数据并将其写入套接字,在套接字上可以在客户端上绘制图形.
客户端,图形,套接字和聚合逻辑都已完成,但我对阅读文件的最佳方法感到困惑.
我尝试过(或者至少玩过)
FIFO – 我可以告诉我的Java进程写入fifo并使用节点读取它,这实际上是我们如何使用Perl实现这一点,但是因为其他所有节点都在节点中运行,所以将代码移植到它上面是有意义的.
Unix套接字 – 如上所述.
fs.watchFile – 这可以满足我们的需求吗?
fs.createReadStream – 这比watchFile好吗?
fs& tail -f – 看起来像个黑客.
实际上,我的问题是什么
我倾向于使用Unix套接字,这似乎是最快的选择.但节点是否具有更好的内置功能,可以实时读取fs中的文件?
解决方法:
如果您希望将文件保留为数据的持久存储,以防止在系统崩溃或网络中正在运行的进程中的某个成员死亡时丢失流,您仍然可以继续写入文件并阅读从中.
如果您不需要将此文件作为Java进程生成结果的持久存储,那么使用Unix套接字对于简易性和性能都要好得多.
fs.watchFile()不是你需要的,因为它适用于文件统计,因为文件系统报告它,因为你想要读取文件,因为它已经被写入,这不是你想要的.
简短更新:我很遗憾地意识到虽然我曾指责fs.watchFile()使用前一段中的文件统计数据,但我在下面的示例代码中自己做了同样的事情!虽然我已经警告读者“要小心!”因为我在几分钟内写完了它,甚至没有测试好;仍然,如果底层系统支持它,可以通过使用fs.watch()而不是watchFile或fstatSync来做得更好.
对于从文件中读取/写入,我在下面的内容中写了以下内容以获得乐趣:
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);
});
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);
}
您可以安全地避免使用nextTick并直接调用readsome().由于我们仍然在这里工作同步,因此在任何意义上都没有必要.我喜欢它. :p
以上面的例子,但扩展它来读取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);
}