Ordinare Un File

Vedi tutte le pagine e le modifiche recenti o scarica i sorgenti nella pagina


OrdinareUnFile

Ordinare un file e’ un operazione banale, e di norma non avremo bisogno di usare ruby per farlo, visto che i sono gia’ piccoli programmini che lo fanno (il classico sort di unix, ad esempio). Eppure e’ utile vedere come farlo con ruby, per aiutare a capire come manipolare i file e come usare i metodi di ordinamento degli oggetti Enumerable

Il metodo piu’ classico e’ questo:

file=File.new('tmp.txt') 
linee=file.readlines
file.close
linee.sort!
file2 = File.new('tmp2.txt','w+')
for linea in linee
 file2.write(linea)
end
file2.close

Che tradotto significa: (1) apri il file tmp.txt (2) metti tutte le linee del file in un array, di nome linee (3) chiudi il file tmp.txt che non serve piu’ (4) ordina l’array in place cioe’ senza crearne un altro (5) apri un nuovo file (6) per ogni elemento dell’array, scrivilo nel file tmp2.txt (7) chiudi tmp2.txt

Questa soluzione e’ semplice, ma un po’ incompleta e un po’ troppo lunga.

Semplifichiamo. Anzitutto possiamo usare open() invece che File.new, il risultato non cambiera’:

file=open('tmp.txt')

poi, potremmo spostare l’operazione di sort nello stesso punto linea in cui leggiamo le linee:

linee=file.readlines.sort!

ed in effetti, non abbiamo bisogno di sort!. Infatti questo metodo serve a modificare un array in place cioe’ senza crearne un altro. Ma a noi l’array non ordinato non serve, ci basta assegnare a linee direttamente quello ordinato:

linee=file.readlines.sort

Il codice dunque, a questo punto sara’ cosi’ :

file=open('tmp.txt') 
linee=file.readlines.sort
file.close
file2 = open('tmp2.txt','w+')
for linea in linee
 file2.write(linea)
end
file2.close

ma quel for... occupa addirittura tre linee, troppa roba. A questo punto ci torna utile ri. infatti, guardate qui:

ri IO.puts ------------ IO#puts ios.puts( [anObject]* ) -> nil

Writes the given objects to ios as with IO#print. Writes a record separator (typically a newline) after any that do not already end with a newline sequence. If called with an array argument, writes each element on a new line.

Notate il dettaglio? Esatto, non ci serve a niente iterare, ci bastera’ passare l’array a puts per vedercelo stampare tutto, un elemento per ogni linea.

Dunque possiamo scrivere:

file=open('tmp.txt') 
linee=file.readlines.sort
file.close
file2 = open('tmp2.txt','w+')
file2.puts(linee)
file2.close

Mh.. si, va gia’ molto meglio. Ma ora notate un altra cosa carina: un oggetto di tipo File include il modulo Enumerable. Questo significa che possiamo usare sort() direttamente su quell’oggetto, senza leggere l’array con readlines. Inoltre, in realta’ non abbiamo bisogno di usare file e file2:

linee=open('tmp.txt').sort
open('tmp2.txt','w+').puts(linee)

Eh si, avete ragione, anche linee non serve a niente: open(‘tmp.txt’,’w+’).puts open(‘tmp.txt’).sort

In effetti, cmq, questa soluzione e’ scorretta. Manca una gestione sensata degli errori.

Gestire gli errori e’ importante. Un metodo classico per farlo e’ racchiudere il codice in un blocco begin..end: begin file=open(‘tmp.txt’) linee=file.readlines.sort file2 = open(‘tmp2.txt’,’w+’) file2.puts(linee) rescue puts “avvenuta eccezione!!” ensure file.close file2.close end

Come vedete, in questo esempio ci preoccupiamo di chiudere i file in ogni caso, e di comunicare evantuali errori all’utente. Avremmo potuto anche racchiudere il tutto in un metodo:

def ordina(filein,fileout)
 file=open(filein) 
 linee=file.readlines.sort
 file2 = open(fileout,'w+')
 file2.puts(linee)
rescue
 puts "avvenuta eccezione!!" 
ensure
 file.close
 file2.close
end

notate come non ci sia bisogno di definire un blocco begin..end, in quanto ruby capisce da solo che il blocco che ci interessa e’ quello del def..end.

Ma se vogliamo davvero una soluzione ottimale, faremo cosi’:

open('tmp2.txt','w+') do |fd|
 fd.puts open('tmp.txt').sort
end

In questa ultima soluzione gli errori vengono gestiti direttamente da open(), non lasciamo nessun descrittore di file aperto. Infatti sara’ la open stessa, alla fine del blocco, a preoccuparsi di richiamare il GC e ripulire tutto. Provate a farlo con un altro linguaggio in maniera altrattanto pulita e chiara :)

Created on November 25, 2005 13:39 by il gruppo (256.256.256.256)