[英]Iterate through lines in a file with Node.js and CoffeeScript
我正在使用带有 CoffeScript 的 Node.js 和以下 function 迭代文件中的行:
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
有没有更好的方法可以在不将整个文件读入 memory 的情况下做到这一点? “更好”是指更简洁,内置于 Node.js 中,更快或更正确。 如果我在写 Python 我会做这样的事情:
def each_line_in(file_obj, func):
[ func(l) for l in file_obj ]
我看到了这个使用Peteris Krumin 的“懒惰”模块的问题,但我想在不添加外部依赖项的情况下完成此操作。
这是一个相当有效的方法:
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
您应该在您的硬件和操作系统上对此进行基准测试,以找到大文件的blockSize
的最佳值。
请注意,这假设文件行仅由\n
划分。 如果您不确定您的文件使用什么,您应该使用正则表达式进行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' 结尾,那将是空的。
我在这三个版本的时间上没有太大差异。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.