使用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的“懒惰” 模块,但我想完成 这没有添加外部依赖项。     

解决方法

        这是一种相当有效的方法:
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个版本的计时上并没有太大区别。