Ruby, как мне разработать парсер? - PullRequest
0 голосов
/ 15 июля 2009

Я пишу небольшой парсер для Google, и я не уверен, как лучше его спроектировать. Основная проблема в том, как он запомнит позицию, в которой остановился.

Во время синтаксического анализа он добавляет новые поиски в конец файла и просматривает файл с первой строки. Теперь я хочу сделать это так, чтобы, если по какой-либо причине выполнение было прервано, сценарий узнает о последнем поиске, который он успешно завершил.

Один из способов - удалить строку в файле после ее извлечения, но в этом случае я должен обработать порядок, в котором потоки обращаются к файлу, и удаление первой строки в файле afaik не может быть эффективно выполнено процессором.

Другой способ - записать номер использованной строки в текстовый файл и пропустить строки, номера которых находятся в этом файле. Или, может быть, мне лучше использовать какую-нибудь базу данных? ТИА

1 Ответ

0 голосов
/ 15 июля 2009

Нет ничего плохого в использовании файла состояния. Единственный улов будет в том, что вам нужно убедиться, что вы полностью зафиксировали свои изменения в файле состояния, прежде чем ваша программа войдет в раздел, где она может быть прервана. Обычно это делается с помощью сброса IO #.

Например, вот простой класс отслеживания состояний, работающий построчно:

class ProgressTracker
  def initialize(filename)
    @filename = filename
    @file = open(@filename)

    @state_filename = File.expand_path(".#{File.basename(@filename)}.position", File.dirname(@filename))

    if (File.exist?(@state_filename))
      @state_file = open(@state_filename, File::RDWR)
      resume!
    else
      @state_file = open(@state_filename, File::RDWR | File::CREAT)
    end
  end

  def each_line
    @file.each_line do |line|
      mark_position!
      yield(line) if (block_given?)
    end
  end

protected
  def mark_position!
    @state_file.rewind
    @state_file.puts(@file.pos)
    @state_file.flush
  end

  def resume!
    if (position = @state_file.readline)
      @file.seek(position.to_i)
    end
  end
end

Вы используете это с IO-подобным вызовом блока:

test = ProgressTracker.new(__FILE__)

n = 0

test.each_line do |line|
  n += 1

  puts "%3d %s" % [ n, line ]

  if (n == 10)
    raise 'terminate'
  end
end

В этом случае программа считывает сама себя и останавливается через десять строк из-за имитированной ошибки. При втором запуске он должен отобразить следующие десять строк, если их так много, или просто выйти, если нет дополнительных данных для извлечения.

Одно предостережение: вам нужно удалить файл .position, связанный с входными данными, если вы хотите, чтобы файл был повторно обработан, или если файл был сброшен. Также невозможно отредактировать файл и удалить более ранние строки, иначе будет отключено отслеживание смещения. Пока вы просто добавляете данные в файл или перезапускаете его, все будет хорошо.

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