问题描述
||
我正在使用带有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的“懒惰”
模块,但我想完成
这没有添加外部依赖项。
解决方法
这是一种相当有效的方法:
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,blockSize,null,callback
lines = buffer.toString(\'utf8\',bytesRead).split \'\\n\'
lines[0] = lastLine + lines[0]
[completeLines...,lastLine] = lines
func(line) for line in completeLines
return
fs.read fd,callback
return
您应该在硬件和操作系统上对此进行基准测试,以找到大文件的最佳值ѭ3。
请注意,这假设文件行仅被“ 4”除。如果您不确定文件使用的是什么,则应为ѭ5使用正则表达式,例如:
.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 \'结尾,则该行将为空。
我在这3个版本的计时上并没有太大区别。