2011-12-30 36 views
8

Ho un file gzip e attualmente ho letto in questo modo:Come si legge un file gzip riga per riga?

infile = open("file.log.gz") 
gz = Zlib::GzipReader.new(infile) 
output = gz.read 
puts result 

penso che questo converte il file in una stringa, ma vorrei leggerlo riga per riga.

Quello che voglio ottenere è che il file ha alcuni messaggi di avviso con un po 'di spazzatura, voglio grep quei messaggi di avviso e poi scriverli in un altro file. Ma alcuni messaggi di avvertimento vengono ripetuti, quindi devo assicurarmi che li annulli solo una volta. Quindi la lettura riga per riga mi aiuterebbe.

risposta

17

si dovrebbe essere in grado di semplicemente ciclo sul lettore gzip come si fa con i flussi regolari (according to the docs)

infile = open("file.log.gz") 
gz = Zlib::GzipReader.new(infile) 
gz.each_line do |line| 
    puts line 
end 
+0

Chiude automaticamente il file al termine della lettura? – Rohit

+3

Sì e no - se GzipReader funziona direttamente su un file, potrebbe essere necessario chiuderlo. Ma in questo caso ho pensato che il metodo 'open' aprisse il file e quindi dovessi chiudere lo stream IO 'inline'. – Tigraine

+2

Wow !! 4 anni dopo e sto ancora rispondendo ai commenti sulla tua risposta. Ora questa è la dedica !! Grazie ancora. – Rohit

1

Prova questo:

infile = open("file.log.gz") 
gz = Zlib::GzipReader.new(infile) 
while output = gz.gets 
    puts output 
end 
+1

L'utilizzo di 'while' funziona, ma' each_line' come mostrato da @Tigraine, è più idiomatico in Ruby. –

+2

Lo so. Ho persino pensato di cancellare la mia risposta, ma poi ho deciso di lasciarlo, per completezza. –

+2

Questa è una buona ragione. Periodicamente mostro modi alternativi per realizzare qualcosa. E, questa è la bellezza di Ruby, possiamo scrivere in stili che sono più vicini a come abbiamo imparato in altre lingue, il che aiuta a renderlo più accessibile e portatile come programmatori. Ciò era in linea con l'obiettivo di Matz di renderlo trasparente allo sviluppatore. –

1

altre risposte mostrano come leggere il file riga per linea, ma non come solo per catturare gli errori una volta. Sulla @ risposta di Tigraine:

require 'set' 

infile = open("file.log.gz") 
gz = Zlib::GzipReader.new(infile) 

errors = Set.new 
# or ... 
# errors = [].to_set 

gz.each_line do |line| 
    errors << line if (line[/^Error:/]) 
    # or ... 
    # errors << line if (line['Error:']) 
end 

puts errors 

Set agisce come Array, ma è costruito utilizzando Hash, quindi è come un Hash ma siamo solo interessati con i tasti, cioè solo i valori univoci vengono memorizzati. Se provi ad aggiungere duplicati, questi verranno buttati via, lasciandoti solo i valori unici. Potresti usare una matrice, e poi usare uniq, ma un Set la gestirà in anticipo.

>> require 'set' 
=> true 
>> errors = Set.new 
=> #<Set: {}> 
>> errors << 'a' 
=> #<Set: {"a"}> 
>> errors << 'b' 
=> #<Set: {"a", "b"}> 
>> errors << 'a' 
=> #<Set: {"a", "b"}>