2009-07-15 9 views
0

J'écris un petit analyseur pour Google et je ne sais pas quelle est la meilleure façon de le concevoir. Le principal problème est la façon dont il se souviendra de la position à laquelle il s'est arrêté.Ruby, comment devrais-je concevoir un analyseur?

Pendant l'analyse, il va ajouter de nouvelles recherches à la fin d'un fichier et parcourir le fichier startig avec la première ligne. Maintenant, je veux le faire, que si pour une raison quelconque l'exécution est interrompue, le script connaît la dernière recherche qu'il a accomplie avec succès. Une façon est de supprimer une ligne dans un fichier après l'avoir récupérée, mais dans ce cas, je dois gérer l'ordre que les threads accèdent au fichier et supprime la première ligne dans un fichier afaik ne peut pas être fait efficacement.

Une autre méthode consiste à écrire le numéro de la ligne utilisée dans un fichier texte et d'ignorer les lignes dont les numéros figurent dans ce fichier. Ou peut-être que je devrais utiliser une base de données à la place? TIA

+0

Avez-vous regardé [Treetop] (http://treetop.rubyforge.org/)? – luccastera

Répondre

0

Il n'y a rien de mal à utiliser un fichier d'état. Le seul inconvénient sera que vous devez vous assurer que vous avez entièrement engagé vos modifications dans le fichier d'état avant que votre programme entre dans une section où il peut être interrompu. Typiquement ceci est fait avec un appel de vidange d'IO #.

Par exemple, voici une simple classe de suivi de l'état qui fonctionne sur une base ligne par ligne:

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 

Vous pouvez l'utiliser avec un appel de bloc IO-like:

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 

Dans ce cas, le programme se lit et s'arrêtera après dix lignes en raison d'une erreur simulée. Lors de la seconde exécution, il devrait afficher les dix lignes suivantes, s'il y en a beaucoup, ou simplement quitter s'il n'y a pas de données supplémentaires à extraire. L'une des mises en garde est que vous devez supprimer le fichier .position associé aux données d'entrée si vous voulez que le fichier soit retraité ou si le fichier a été réinitialisé. Il n'est pas non plus possible de modifier le fichier et de supprimer les lignes précédentes, sinon le suivi de décalage sera désactivé. Tant que vous ajoutez simplement des données au fichier ou que vous le redémarrez, tout ira bien.