Input/Output da file¶
I file si aprono e chiudono con open e close, con le flags rwa... presenti anche in C
Di solito conviene aprire un file in un blocco with in modo da non doversi ricordare di chiuderlo in modo
esplicito.
Cosa sono le flag dei files¶
Cosa vogliamo fare con un file aperto dalla funzione open è stabilito da una flag che passiamo alla funzione stessa.
r: apri in lettura.w: apri in scrittura. Il file viene sovrascritto.a: apri in modalità "append", nuovi dati vengono aggiunti alla fine del file.
Es Scrivere un file¶
filename = './data/file0.txt'
ungaretti = """Soldati
Si sta come
d'autunno
sugli alberi
le foglie
"""
sosa = """Todo Cambia
Cambia lo superficial
Cambia también lo profundo
Cambia el modo de pensar
Cambia todo en este mundo
...
"""
with open(filename,'w') as file_out:
file_out.write(ungaretti)
file_out = open(filename,'w')
file_out.write(ungaretti)
file_out.close()
Vediamo che lo abbia effettivamente scritto. Apritelo con un editor di testo.
!cat ./data/file0.txt
Soldati Si sta come d'autunno sugli alberi le foglie
Se ora riapro il file in lettura, questo viene sovrascritto!
with open(filename,'w') as file_out:
file_out.write(sosa)
!cat ./data/file0.txt
Todo Cambia Cambia lo superficial Cambia también lo profundo Cambia el modo de pensar Cambia todo en este mundo ...
Appendere in coda ad un file¶
Per evitare di sovrascrivere un file, uso a.
with open(filename,'a') as file_out:
file_out.write(ungaretti)
!cat ./data/file0.txt
Todo Cambia Cambia lo superficial Cambia también lo profundo Cambia el modo de pensar Cambia todo en este mundo ... Soldati Si sta come d'autunno sugli alberi le foglie
Leggere i file¶
Basta usare r, e chiamare poi o la funzione readlines() per leggere tutte le righe in una lista, oppure readline in un ciclo per leggere le righe una alla volta.
with open(filename,'r') as file_in:
lines = file_in.readlines()
#print(lines)
for l in lines:
print(l,end="") # print aggiunge un newline! provate print(l,end='')
Todo Cambia Cambia lo superficial Cambia también lo profundo Cambia el modo de pensar Cambia todo en este mundo ... Soldati Si sta come d'autunno sugli alberi le foglie
Le linee che abbiamo letto ora sono salvate in una lista. Ogni elemento di questa lista è una stringa. Questo è un aspetto importante da ricordare:
readline() e readlines() restituiscono sempre stringhe!
lines
['Todo Cambia \n', '\n', 'Cambia lo superficial\n', 'Cambia también lo profundo\n', 'Cambia el modo de pensar\n', 'Cambia todo en este mundo\n', '...\n', '\n', 'Soldati\n', '\n', 'Si sta come\n', "d'autunno\n", 'sugli alberi\n', 'le foglie\n', '\n']
Ricostruire il contenuto testuale¶
Visto che abbiamo una lista di stringhe, se vogliamo concatenarle a formare un'unica stringa di testo contenente spazi, a capi, etc, possiamo sfruttare il fatto che l'operatore + concatena le stringhe e fare come segue.
testo = ""
for l in lines:
testo = testo + l
print(testo)
Todo Cambia Cambia lo superficial Cambia también lo profundo Cambia el modo de pensar Cambia todo en este mundo ... Soldati Si sta come d'autunno sugli alberi le foglie
Scrivere file riga per riga¶
Nella maggior parte dei casi vogliamo scrivere i file una riga alla volta. Le nostre righe sono in genere formattate per contenere i risultati di calcoli, con diverse colonne che corrispondono ai valori di diversi osservabili in misurazioni (o iterazioni di un calcolo) successive.
Per scrivere righe separate dobbiamo ricordare il carattere di fine riga: \n.
from math import sin, asin
filename = './data/test.dat'
#fin = open(filename,'w')
#fin.write('this but a scratch\n')
#fin.close()
with open(filename,'w') as file_out:
for n in range(10):
file_out.write(f"{n} {sin(n*2*3.1315/10)}\n")
!cat ./data/test.dat
0 0.0 1 0.5861510302917453 2 0.9498012490079234 3 0.9529103480837178 4 0.5942981247524649 5 0.010092482248263786 6 -0.5779442300229447 7 -0.9465954024248175 8 -0.9559223829569071 9 -0.6023846835356105
Leggere le righe una per volta e agire su ognuna¶
In alcuni casi può essere utile leggere solo una parte di un file, oppure leggere le righe una alla volta, fare dei calcoli, e caricare solo il risultato di questi. In generale, questo è vero quando si lavora con file piuttosto grandi, dalle centinaia di Mb / 1Gb in su, specie su computer con pochi Gb di RAM.
fin = open(filename,'r')
fin.readline() # prima riga
'0 0.0\n'
fin.readline() # seconda riga, e così via
'1 0.5861510302917453\n'
fin.close() # chiudo il file esplicitamente
Esempio, leggiamo solo il file di prima e calcoliamo gli angoli corrispondenti ai soli seni positivi¶
per ciclare sulle righe in ingresso in C useremo un while. In Python si può usare un ciclo for perché essendo il linguaggio ad oggetti, questo viene ridefinito per i file, che sono classi, come "scorri tutte le righe".
with open('./data/test.dat','r') as file_in:
angles = []
for line in file_in:
# 1. separiamo le colonne
d = line.split() # trasforma l in un array
# 2. trasformiamo in float
t = int(d[0])
s = float(d[1])
if s>0:
angles.append([t,s,asin(s)])
Il risultato ora è quello atteso. Notare che nella funzione print qui sotto usiamo anche alcuni elementi per formattare il testo: :d dice di trattare un valore come un numero intero, mentre :.Nfstampa un numero floating-point con N cifre dopo il punto decimale.
for data in angles:
print(f"angle[{data[0]:d}]:{data[1]:.4f} sin:{data[2]:.4f}")
angle[1]:0.5862 sin:0.6263 angle[2]:0.9498 sin:1.2526 angle[3]:0.9529 sin:1.2627 angle[4]:0.5943 sin:0.6364 angle[5]:0.0101 sin:0.0101
Formattare l'output¶
Quando stampiamo un file è bene formattarlo in modo comprensibile, in modo che sia poi facile da analizzare.
Consideriamo un file .csv (o .dat), in cui colonne di numeri sono separate da carattere.
- Scegliamo un separatore univoco: spazi
o\t(file.dat) oppure la virgola,o il;se non li usiamo in altri contesti. - Mettiamo un header che inizia con
#nella prima riga per spiegare cosa c'è in ogni colonna. - Se abbiamo anche testo mescolato, stiamo attenti a come scegliamo ulteriori separatori in modo che siano facili da individuare.
- Teniamo abbastanza valori dopo la virgola da non perdere precisione numerica!
x=0.1/3.1415
f"{x:.5f}\n" #stamp x con 5 cifre dopo la virgola
numpy.savetxt ci aiuta molto in questo:
import numpy as np
l = np.linspace(0,2*np.pi,10)
np.savetxt('./data/sin.dat', np.column_stack([l,np.sin(l)]),header="x\tsin(x)",fmt="%.6f")
!cat ./data/sin.dat
# x sin(x) 0.000000 0.000000 0.698132 0.642788 1.396263 0.984808 2.094395 0.866025 2.792527 0.342020 3.490659 -0.342020 4.188790 -0.866025 4.886922 -0.984808 5.585054 -0.642788 6.283185 -0.000000