繁体   English   中英

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

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM