Ogni volta che usiamo Python lo facciamo operando in una cartella di lavoro
Per sapere dove stiamo lavorando uso il modulo (package) os ed in particolare il modulo os.path:
import os
os.getcwd()
Posso cambiare cartella specificando un percorso 'relativo' alla cartella di lavoro corrente
os.chdir('..')
print(os.path.abspath(os.curdir))
Oppure utilizzando un percorso assoluto:
os.chdir('C:/python/corso/lezioni')
print(os.path.abspath(os.curdir))
documentazione di open in py3k-doc
La funzione open accetta molti parametri di cui due sono fondamentali:
Per poter scrivere un file di testo e' necessario prima aprirlo (o crearlo come in questo caso) in modalita' testuale e in scrittura:
#apro un file in scrittura specificandone nome 'mytxt.txt' e
#che voglio aprirlo in modalita' testuale ed in scrittura!
myfl = open('mytxt.txt','wt')
type(myfl),dir(myfl)
Per scrivere si usa principalmente il metodo write dell'oggetto file restituito da open.
Il metodo write accetta come argomenti delle stringhe e se voglio scrivere sul file un numero o altro devo convertirlo prima in stringa (siamo in modalita' testuale).
myfl.write('questa è una stringa\n')
myfl.write('sulla riga seguente c\' è un numero\n')
myfl.write(str(10)+'\n')
myfl.close()
Per chi vuole scrivere un elenco di rige c'e' writelines:
rows=[]
for i in range(1,11):
rows.append('stringa {0}\n'.format(i))#provare con e senza \n
#sovrascrivo il file
myfl = open('mytxt.txt','wt')
myfl.writelines(rows)
#myfl.writelines(rows)
# è equivalente a
#for row in rows:
# myfl.write(row)
myfl.close()
Il carattere \n e' il fine riga e, in modalita' testuale, viene scritto sul file in modo diverso a seconda della piattaforma utilizzata (ad esempio in windows viene 'tradotto in due caratteri)
myfl = open('mytxt.txt','a')# t non necessario
nc = myfl.write('\nun\'altra stringa con carattere con un carattere non ascii: è \n')
print('ho scritto altri {0} caratteri nell file'.format(nc))
myfl.close()
#apro il file in lettura
myfl = open('mytxt.txt')# (default 'rt')
#leggo tutto in una riga
mystr=myfl.read()
#chiudo il file
myfl.close()
#stampo la stringa
print(mystr)
mystr
#apro il file in lettura
myfl = open('mytxt.txt')
#leggo in una lista di stringhe
rows=myfl.readlines()
#chiudo il file
myfl.close()
#stampo la lista
print(rows)
#stampo le stringhe della lista
for row in rows:
print(row, end="")#due \n uno nella riga, uno aggiunto da
#print, usare row.strip() per eliminare il primo
#o il parametro end di print per eliminare il secondo
#apro il file in lettura
myfl = open('mytxt.txt')
row = "segnaposto"
while row:
row=myfl.readline()
print(row,end='')
myfl.close()
#apro il file in lettura
myfl = open('mytxt.txt','r')
for row in myfl:
print(row,end='')
myfl.close()
Vediamo un esempio:
with open('mytxt.txt') as f:
rows = f.readlines()
#il file viene chiuso
#uso le stringhe memorizzate nella lista rows
for i,row in enumerate(rows):
print(row.rstrip()*i)
Stabiliamo le specifiche del file:
<li>riga delle intestazioni delle ncols colonne 'intestazione-01,....intestazione-ncol'</li>
<li>seguono un numero nrows indefinito di righe ciascuna con ncol colonne (nrows, ncols indefiniti in lettura)</li>
<li>nella iesima riga e jesima colonna dati c' è l'intero j*10**(i) dove i e j partono da zero</li>
Il file da scrivere e leggere avra cio é la seguente struttura
In particolare:
ncols = 10
nrows = 10
#....
intestazioni = ['intestaz-{0:02d}'.format(i) for i in range (1,ncols+1)]
righe =[ [str(icol*10**(irow)) for icol in range(ncols)] for irow in range(nrows)]
with open('provacsv.csv','wt') as fl:
fl.write(','.join(intestazioni)+'\n')
for colonne in righe:
fl.write(','.join(colonne)+'\n')
#versione -2
#scrivo una riga per volta generando contestualmente i dati
with open('provacsv2.csv','wt') as fl:
for j in range(ncols):
fl.write('Intestazione-{0:02d},'.format(j+1))
fl.write('\n')
for i in range(nrows):
for j in range(ncols):
fl.write(str(j*(10**i))+',')
fl.write('\n')
#carico i dati scritti nel file tutti in una botta
with open('provacsv.csv','rt') as fl:
rows=fl.readlines()
intestazioni = [i.rstrip() for i in rows[0].split(',')]
dati = []
for row in rows[1:]:
datiriga = [ int(i) for i in row.split(',')]
dati.append(datiriga)
#verifica lettura v1
print(intestazioni)
for r in dati:
print(r)
dati2 = []
with open('provacsv2.csv','rt') as fl:
for i,row in enumerate(fl):
if i==0:
intestazioni2 = [i.rstrip() for i in rows[0].split(',')]
else:
dati2.append([int(i) for i in row.split(',') if len(i.rstrip())>0])
#verifica lettura v2
print(intestazioni2)
for r in dati2:
print(r)
Per leggere e contemporaneamente scrivere su un file si usano le modalita' (analoghe alla funzione fopen in C):
Vediamo un esempio.
Scriviamo un file di testo:
# ATTENZIONE se uso un file assegnandogli
# lo stesso nome (myfl)
# che utilizzo in un successivo costrutto with (anche se riferito ad un diverso file su disco)
# dopo il blocco with vengono chiusi entrambi i files
#prove effettuate in aula
#myfl = open('mytxt2.txt','wt')
#myfl.write('ciao')
with open('mytxt.txt','wt') as myfl:
for i in range(1,10):
s='stringa {0}\n'.format(i)
myfl.write(s)
print(s, end="")
#LE SEGUENTI ISTRUZIONI GENERANO UN ERRORE
#myfl.write('ciao ciao')
#myfl.close()
Adesso leggiamo il file appena creato e contestualmente lo modifichiamo.
Per farlo, oltre alle funzioni gi à viste usiamo:
#AGGIUNGO UNA RIGA ALL'INIZIO
#apro il file in lettura + scrittura, scrivo all'inizio
myfl = open('mytxt.txt','r+')
myfl.write('stringa x\n')
#AGGIUNGO UNA RIGA ALLA FINE
#torno all'inizio del file
myfl.seek(0)
rows1 = myfl.readlines()
myfl.write('riga aggiunta alla fine!!!')
#MODIFICO LA TERZA RIGA
#torno all'inizio del file
myfl.seek(0)
#leggo due righe e le stampo
print('ho letto la riga: ',myfl.readline(),end="")
print('ho letto la riga: ',myfl.readline(),end="")
#devo spostare il puntatore esplicitamente
#altrimenti il successivo write scrive alla fine
myfl.seek(myfl.tell(),0)
#modifico la terza riga
myfl.write('stringa y\n')
#RILEGGO PER INTERO IL FILE MODIFICATO
#torno all'inizio del file altrimenti non leggo le righe aggiunte
myfl.seek(0)
rows2 = myfl.readlines()
myfl.close()
print('-----file modificato-----')
for row in rows2:
print(row,end="")
print('\n-----fine file modificato-----')
with open('mybinfl.bin','wb') as myflbin:
myflbin.write(bytes(range(1,10)))
nota bene i flag rb passati a open
with open('mybinfl.bin','rb') as myflbin:
#leggo tutto il contenuto in un'unica stringa di bytes
data=myflbin.read()
print(data)
with open('mybinfl.bin','rb') as myflbin:
#leggo il primo byte
b0=myflbin.read(1)
#mi sposto al quarto byte
myflbin.seek(4,0)
#leggo i due bytes successivi al quarto
b45=myflbin.read(2)
print(b0)
print(b45)
#scrivo un intero, una stringa, su un file binario,
#dopo averli convertiti in bytes
#con un float e' + laborioso ed e' meglio usare l'approccio 2
i = 2
s = 'ciao'
print('Scrivo su un file (binario) :\n',i,s)
with open('mybinfl.bin','wb') as myflbin:
myflbin.write(bytes([i]))
myflbin.write(bytes(s,encoding='ascii'))
#leggo il file
with open('mybinfl.bin','rb') as myflbin:
data=myflbin.read()
print('Il contenuto del file (in bytes) è :\n',data)
#decodifico il contenuto
ii=int(data[0])
ss=str(data[1:],encoding='ascii')
print('Il contenuto del file decodificato è :\n',ii,ss)
Uso il modulo standard struct
Questo modulo effettua conversioni tra vari tipi di dati in Python e i bytes di Python. Cio' puo' essere utile nel trattamento dei dati binari memorizzati in file. Utilizza stringhe di formato come descrizioni compatte del layout delle strutture dati e la conversione a / da valori Python.
Le principali funzioni del modulo struct sono:
Segue la tabella dei caratteri che compongono la stringa di formato usata in pack ed unpack:
fl=open('mybinfl.bin','wb')
fl.write(bytes([]))
fl.close()
import struct
#scrivo un intero, una stringa, su un file binario,
#dopo averli convertiti in bytes
#con un float e' molto + laborioso ed e' meglio usare l'approccio 2
i = 2
s = 'ciao'
f = 12.456
print('Scrivo su un file (binario) :\n',i,s,f)
with open('mybinfl.bin','wb') as myflbin:
#trasformo i s e f in Bytes
dataw = struct.pack('@i4sd',i,s.encode('ascii'),f)
print('in Bytes:')
print(dataw)
myflbin.write(dataw)
#leggo il file
with open('mybinfl.bin','rb') as myflbin:
datar=myflbin.read()
print('Il contenuto del file (in bytes) è :\n',datar)
#decodifico il contenuto
ii,ss,ff=struct.unpack('@i4sd',datar)
print('Il contenuto del file decodificato è :\n',ii,ss.decode('ascii'),ff)
Tutte le operazioni di scrittura e lettura di file viste fino ad ora possono essere effettuate anche in memoria volatile usando le classi StringIO (modalita' testuale) e BytesIO (modalita' binaria).
In pratica le due classi
Vedi anche in-memory-streams
scrivo in memoria
import io
#creo un oggetto 'file-like' testuale in memoria
output = io.StringIO()
#scrivo con write come su un file di testo
output.write('Prima riga\n')
#scrivo con print specificando il file
print('Seconda riga.\n', file=output)
leggo dalla memoria
#Recupero l'intero contenuto del file
#dopo aver riportato il puntatore all'inizio
output.seek(0)
contents = output.read()
# chiudo l'oggetto e cancello i dati dalla memoria
# dopo la chiusura una chiamata a read o a write provocherebbe un errore
output.close()
print(contents)