Перебирать строки в файле с помощью Node.js и CoffeeScript - PullRequest
5 голосов
/ 12 июня 2011

Я перебираю строки в файле, используя Node.js с CoffeScript и следующей функцией:

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 ]

Я видел этот вопрос , который использует модуль "Ленивый" Петериса Крумина , но я бы хотелчтобы выполнить это без добавления внешней зависимости.

Ответы [ 2 ]

6 голосов
/ 12 июня 2011

Вот довольно эффективный подход:

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/)
0 голосов
/ 05 февраля 2013

Это краткая версия с использованием 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 версий.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...