用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'结尾,则该行将是空的。
这三个版本的时间差别不大。