用Node.js和CoffeeScript遍历文件中的行

我使用CoffeScript和以下函数使用Node.js来遍历文件中的行:

each_line_in = (stream, func) -> fs.stat stream.path, (err, stats) -> previous = [] stream.on 'data', (d) -> start = cur = 0 for c in d cur++ if c == 10 previous.push(d.slice(start, cur)) func previous.join('') previous = [] start = cur previous.push(d.slice(start, cur)) if start != cur 

有没有更好的办法做到这一点,而不是整个文件读入内存? “更好”的意思是更简洁,内置Node.js,更快,更准确。 如果我正在写Python,我会做这样的事情:

 def each_line_in(file_obj, func): [ func(l) for l in file_obj ] 

我看到了这个使用Peteris Krumin的“lazy”模块的问题 ,但是我想完成这个不添加外部依赖的工作。

这是一个相当有效的方法:

 eachLineIn = (filePath, func) -> blockSize = 4096 buffer = new Buffer(blockSize) fd = fs.openSync filePath, 'r' lastLine = '' callback = (err, bytesRead) -> throw err if err if bytesRead is blockSize fs.read fd, buffer, 0, blockSize, null, callback lines = buffer.toString('utf8', 0, bytesRead).split '\n' lines[0] = lastLine + lines[0] [completeLines..., lastLine] = lines func(line) for line in completeLines return fs.read fd, buffer, 0, blockSize, 0, callback return 

您应该在您的硬件和操作系统上进行基准testing,以查找大型文件的最佳blockSize值。

请注意,这是假定文件行仅由\n划分。 如果你不确定你的文件使用什么,你应该使用正则expression式来split ,例如:

 .split(/(\\r\\n)|\\r|\\n/) 

这是一个使用ReadStream的简洁版本,例如stream = fs.createReadStream(filepath)

 for_each_line = (stream, func) -> last = "" stream.on('data', (chunk) -> lines = (last + chunk).split("\n") [lines...,last] = lines for line in lines func(line) ) stream.on('end', () -> func(last) ) 

createReadStream选项可以根据需要设置缓冲区大小和编码。

这会去掉'\ n',但是如果需要的话可以加回去。 它也处理最后一行,但如果文件以'\ n'结尾,则该行将是空的。

这三个版本的时间差别不大。