2013-05-24 16 views
6

Questo funziona:C'è un modo per cercare attraverso un file senza caricare l'intera cosa in un array?

f = File.new("myfile").readlines 
f[0] #=> "line 1" 
f[21] #=> "line 22" 

Ma cosa succede se ho un file molto grande, e solo bisogno di leggere qualche riga. È possibile cercare linee specifiche e leggerle in Ruby, senza caricare il file in un array?

I groove flussi IO, dove (come nel caso di stdin) non è possibile cercare casualmente attraverso un flusso. Sicuramente ci deve essere un modo per farlo senza caricare l'intero file.

risposta

5

Allo scopo è possibile utilizzare la each_line iteratore, combinata con with_index avere il numero di riga della riga corrente (contando da 0):

File.open('myfile') do |file| 

    file.each_line.with_index do |line, lineno| 
    case lineno 
    when 0 
     # line 1 
    when 21 
     # line 22 
    end 
    end 

end 

Utilizzando open, passando un blocco di esso, invece di new, è garantito che il file viene chiuso correttamente alla fine dell'esecuzione del blocco.


Aggiornamento Il metodo with_index accetta un argomento opzionale per specificare l'indice di partenza da utilizzare, il codice in modo Che di cui sopra potrebbe essere meglio scritto così:

file.each_line.with_index(1) do |line, lineno| 
    case lineno 
    when 1 
    # line 1 
    end 
end 
2

Ho usato risposte Jack e toro2k di (più o meno la stessa risposta), ma modificata per il mio caso d'uso. Dove posso desiderare: aprire un file e cercare più righe casuali, in cui l'ordine potrebbe non essere sempre sequenziale. Questo è ciò che mi è venuta (astratta):

class LazyFile 
    def initialize(file) 
     @content = File.new(file) 
    end 

    def [](lineno) 
     @content.rewind if @content.lineno > lineno 
     skip = lineno - @content.lineno 
     skip.times { @content.readline } 
     @content.readline 
    end 
end 

file = LazyFile("myfile") 
file[1001] 
7

Non ignorare la classe IO. IO::foreach è uno di quei metodi che restituisce un enumeratore e può essere valutato pigramente.

IO#each_line è anche un altro che restituirà un enumeratore.

In Ruby 2.0 possiamo chiamare .lazy e utilizzare questi metodi, ad eccezione di zip e ciclo, che ci consentono di attraversare l'enumerazione senza portare l'intero file in memoria.

Problemi correlati